1*4b22b933Srs200217 /* -*- Mode: C; tab-width: 4 -*-
2*4b22b933Srs200217 *
3*4b22b933Srs200217 * Copyright (c) 2002-2006 Apple Computer, Inc. All rights reserved.
4*4b22b933Srs200217 *
5*4b22b933Srs200217 * Licensed under the Apache License, Version 2.0 (the "License");
6*4b22b933Srs200217 * you may not use this file except in compliance with the License.
7*4b22b933Srs200217 * You may obtain a copy of the License at
8*4b22b933Srs200217 *
9*4b22b933Srs200217 * http://www.apache.org/licenses/LICENSE-2.0
10*4b22b933Srs200217 *
11*4b22b933Srs200217 * Unless required by applicable law or agreed to in writing, software
12*4b22b933Srs200217 * distributed under the License is distributed on an "AS IS" BASIS,
13*4b22b933Srs200217 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14*4b22b933Srs200217 * See the License for the specific language governing permissions and
15*4b22b933Srs200217 * limitations under the License.
16*4b22b933Srs200217 *
17*4b22b933Srs200217 * This code is completely 100% portable C. It does not depend on any external header files
18*4b22b933Srs200217 * from outside the mDNS project -- all the types it expects to find are defined right here.
19*4b22b933Srs200217 *
20*4b22b933Srs200217 * The previous point is very important: This file does not depend on any external
21*4b22b933Srs200217 * header files. It should complile on *any* platform that has a C compiler, without
22*4b22b933Srs200217 * making *any* assumptions about availability of so-called "standard" C functions,
23*4b22b933Srs200217 * routines, or types (which may or may not be present on any given platform).
24*4b22b933Srs200217
25*4b22b933Srs200217 * Formatting notes:
26*4b22b933Srs200217 * This code follows the "Whitesmiths style" C indentation rules. Plenty of discussion
27*4b22b933Srs200217 * on C indentation can be found on the web, such as <http://www.kafejo.com/komp/1tbs.htm>,
28*4b22b933Srs200217 * but for the sake of brevity here I will say just this: Curly braces are not syntactially
29*4b22b933Srs200217 * part of an "if" statement; they are the beginning and ending markers of a compound statement;
30*4b22b933Srs200217 * therefore common sense dictates that if they are part of a compound statement then they
31*4b22b933Srs200217 * should be indented to the same level as everything else in that compound statement.
32*4b22b933Srs200217 * Indenting curly braces at the same level as the "if" implies that curly braces are
33*4b22b933Srs200217 * part of the "if", which is false. (This is as misleading as people who write "char* x,y;"
34*4b22b933Srs200217 * thinking that variables x and y are both of type "char*" -- and anyone who doesn't
35*4b22b933Srs200217 * understand why variable y is not of type "char*" just proves the point that poor code
36*4b22b933Srs200217 * layout leads people to unfortunate misunderstandings about how the C language really works.)
37*4b22b933Srs200217
38*4b22b933Srs200217 Change History (most recent first):
39*4b22b933Srs200217
40*4b22b933Srs200217 $Log: mDNS.c,v $
41*4b22b933Srs200217 Revision 1.537.2.1 2006/08/29 06:24:22 cheshire
42*4b22b933Srs200217 Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
43*4b22b933Srs200217
44*4b22b933Srs200217 Revision 1.537 2006/03/19 02:00:07 cheshire
45*4b22b933Srs200217 <rdar://problem/4073825> Improve logic for delaying packets after repeated interface transitions
46*4b22b933Srs200217
47*4b22b933Srs200217 Revision 1.536 2006/03/08 23:29:53 cheshire
48*4b22b933Srs200217 <rdar://problem/4468716> Improve "Service Renamed" log message
49*4b22b933Srs200217
50*4b22b933Srs200217 Revision 1.535 2006/03/02 20:41:17 cheshire
51*4b22b933Srs200217 <rdar://problem/4111464> After record update, old record sometimes remains in cache
52*4b22b933Srs200217 Minor code tidying and comments to reduce the risk of similar programming errors in future
53*4b22b933Srs200217
54*4b22b933Srs200217 Revision 1.534 2006/03/02 03:25:46 cheshire
55*4b22b933Srs200217 <rdar://problem/4111464> After record update, old record sometimes remains in cache
56*4b22b933Srs200217 Code to harmonize RRSet TTLs was inadvertently rescuing expiring records
57*4b22b933Srs200217
58*4b22b933Srs200217 Revision 1.533 2006/02/26 00:54:41 cheshire
59*4b22b933Srs200217 Fixes to avoid code generation warning/error on FreeBSD 7
60*4b22b933Srs200217
61*4b22b933Srs200217 Revision 1.532 2005/12/02 20:24:36 cheshire
62*4b22b933Srs200217 <rdar://problem/4363209> Adjust cutoff time for KA list by one second
63*4b22b933Srs200217
64*4b22b933Srs200217 Revision 1.531 2005/12/02 19:05:42 cheshire
65*4b22b933Srs200217 Tidy up constants
66*4b22b933Srs200217
67*4b22b933Srs200217 Revision 1.530 2005/11/07 01:49:48 cheshire
68*4b22b933Srs200217 For consistency, use NonZeroTime() function instead of ?: expression
69*4b22b933Srs200217
70*4b22b933Srs200217 Revision 1.529 2005/10/25 23:42:24 cheshire
71*4b22b933Srs200217 <rdar://problem/4316057> Error in ResolveSimultaneousProbe() when type or class don't match
72*4b22b933Srs200217 Changed switch statement to an "if"
73*4b22b933Srs200217
74*4b22b933Srs200217 Revision 1.528 2005/10/25 23:34:22 cheshire
75*4b22b933Srs200217 <rdar://problem/4316048> RequireGoodbye state not set/respected sometimes when machine going to sleep
76*4b22b933Srs200217
77*4b22b933Srs200217 Revision 1.527 2005/10/25 22:43:59 cheshire
78*4b22b933Srs200217 Add clarifying comments
79*4b22b933Srs200217
80*4b22b933Srs200217 Revision 1.526 2005/10/20 00:10:33 cheshire
81*4b22b933Srs200217 <rdar://problem/4290265> Add check to avoid crashing NAT gateways that have buggy DNS relay code
82*4b22b933Srs200217
83*4b22b933Srs200217 Revision 1.525 2005/09/24 00:47:17 cheshire
84*4b22b933Srs200217 Fix comment typos
85*4b22b933Srs200217
86*4b22b933Srs200217 Revision 1.524 2005/09/16 21:06:49 cheshire
87*4b22b933Srs200217 Use mDNS_TimeNow_NoLock macro, instead of writing "mDNSPlatformRawTime() + m->timenow_adjust" all over the place
88*4b22b933Srs200217
89*4b22b933Srs200217 Revision 1.523 2005/03/21 00:33:51 shersche
90*4b22b933Srs200217 <rdar://problem/4021486> Fix build warnings on Win32 platform
91*4b22b933Srs200217
92*4b22b933Srs200217 Revision 1.522 2005/03/04 21:48:12 cheshire
93*4b22b933Srs200217 <rdar://problem/4037283> Fractional time rounded down instead of up on platforms with coarse clock granularity
94*4b22b933Srs200217
95*4b22b933Srs200217 Revision 1.521 2005/02/25 04:21:00 cheshire
96*4b22b933Srs200217 <rdar://problem/4015377> mDNS -F returns the same domain multiple times with different casing
97*4b22b933Srs200217
98*4b22b933Srs200217 Revision 1.520 2005/02/16 01:14:11 cheshire
99*4b22b933Srs200217 Convert RR Cache LogOperation() calls to debugf()
100*4b22b933Srs200217
101*4b22b933Srs200217 Revision 1.519 2005/02/15 01:57:20 cheshire
102*4b22b933Srs200217 When setting "q->LastQTxTime = m->timenow", must also clear q->RecentAnswerPkts to zero
103*4b22b933Srs200217
104*4b22b933Srs200217 Revision 1.518 2005/02/10 22:35:17 cheshire
105*4b22b933Srs200217 <rdar://problem/3727944> Update name
106*4b22b933Srs200217
107*4b22b933Srs200217 Revision 1.517 2005/02/03 00:21:21 cheshire
108*4b22b933Srs200217 Update comments about BIND named and zero-length TXT records
109*4b22b933Srs200217
110*4b22b933Srs200217 Revision 1.516 2005/01/28 06:06:32 cheshire
111*4b22b933Srs200217 Update comment
112*4b22b933Srs200217
113*4b22b933Srs200217 Revision 1.515 2005/01/27 00:21:49 cheshire
114*4b22b933Srs200217 <rdar://problem/3973798> Remove mDNSResponder sleep/wake syslog message
115*4b22b933Srs200217
116*4b22b933Srs200217 Revision 1.514 2005/01/21 01:33:45 cheshire
117*4b22b933Srs200217 <rdar://problem/3962979> Shutdown time regression: mDNSResponder not responding to SIGTERM
118*4b22b933Srs200217
119*4b22b933Srs200217 Revision 1.513 2005/01/21 00:07:54 cheshire
120*4b22b933Srs200217 <rdar://problem/3962717> Infinite loop when the same service is registered twice, and then suffers a name conflict
121*4b22b933Srs200217
122*4b22b933Srs200217 Revision 1.512 2005/01/20 00:37:45 cheshire
123*4b22b933Srs200217 <rdar://problem/3941448> mDNSResponder crashed in mDNSCoreReceiveResponse
124*4b22b933Srs200217 Take care not to recycle records while they are on the CacheFlushRecords list
125*4b22b933Srs200217
126*4b22b933Srs200217 Revision 1.511 2005/01/19 22:48:53 cheshire
127*4b22b933Srs200217 <rdar://problem/3955355> Handle services with subtypes correctly when doing mDNS_RenameAndReregisterService()
128*4b22b933Srs200217
129*4b22b933Srs200217 Revision 1.510 2005/01/19 03:12:45 cheshire
130*4b22b933Srs200217 Move LocalRecordReady() macro from mDNS.c to DNSCommon.h
131*4b22b933Srs200217
132*4b22b933Srs200217 Revision 1.509 2005/01/19 03:08:49 cheshire
133*4b22b933Srs200217 <rdar://problem/3961051> CPU Spin in mDNSResponder
134*4b22b933Srs200217 Log messages to help catch and report CPU spins
135*4b22b933Srs200217
136*4b22b933Srs200217 Revision 1.508 2005/01/18 18:56:32 cheshire
137*4b22b933Srs200217 <rdar://problem/3934245> QU responses not promoted to multicast responses when appropriate
138*4b22b933Srs200217
139*4b22b933Srs200217 Revision 1.507 2005/01/18 01:12:07 cheshire
140*4b22b933Srs200217 <rdar://problem/3956258> Logging into VPN causes mDNSResponder to reissue multicast probes
141*4b22b933Srs200217
142*4b22b933Srs200217 Revision 1.506 2005/01/17 23:28:53 cheshire
143*4b22b933Srs200217 Fix compile error
144*4b22b933Srs200217
145*4b22b933Srs200217 Revision 1.505 2005/01/11 02:02:56 shersche
146*4b22b933Srs200217 Move variable declaration to the beginning of statement block
147*4b22b933Srs200217
148*4b22b933Srs200217 Revision 1.504 2004/12/20 20:24:35 cheshire
149*4b22b933Srs200217 <rdar://problem/3928456> Network efficiency: Don't keep polling if we have at least one unique-type answer
150*4b22b933Srs200217
151*4b22b933Srs200217 Revision 1.503 2004/12/20 18:41:47 cheshire
152*4b22b933Srs200217 <rdar://problem/3591622> Low memory support: Provide answers even when we don't have cache space
153*4b22b933Srs200217
154*4b22b933Srs200217 Revision 1.502 2004/12/20 18:04:08 cheshire
155*4b22b933Srs200217 <rdar://problem/3923098> For now, don't put standard wide-area unicast responses in our main cache
156*4b22b933Srs200217
157*4b22b933Srs200217 Revision 1.501 2004/12/19 23:50:18 cheshire
158*4b22b933Srs200217 <rdar://problem/3751638> kDNSServiceInterfaceIndexLocalOnly should return all local records
159*4b22b933Srs200217 Don't show "No active interface to send" messages for kDNSServiceInterfaceIndexLocalOnly services
160*4b22b933Srs200217
161*4b22b933Srs200217 Revision 1.500 2004/12/18 03:13:46 cheshire
162*4b22b933Srs200217 <rdar://problem/3751638> kDNSServiceInterfaceIndexLocalOnly should return all local records
163*4b22b933Srs200217
164*4b22b933Srs200217 Revision 1.499 2004/12/17 23:37:45 cheshire
165*4b22b933Srs200217 <rdar://problem/3485365> Guard against repeating wireless dissociation/re-association
166*4b22b933Srs200217 (and other repetitive configuration changes)
167*4b22b933Srs200217
168*4b22b933Srs200217 Revision 1.498 2004/12/17 05:25:46 cheshire
169*4b22b933Srs200217 <rdar://problem/3925163> Shorten DNS-SD queries to avoid NAT bugs
170*4b22b933Srs200217
171*4b22b933Srs200217 Revision 1.497 2004/12/17 03:20:58 cheshire
172*4b22b933Srs200217 <rdar://problem/3925168> Don't send unicast replies we know will be ignored
173*4b22b933Srs200217
174*4b22b933Srs200217 Revision 1.496 2004/12/16 22:18:26 cheshire
175*4b22b933Srs200217 Make AddressIsLocalSubnet() a little more selective -- ignore point-to-point interfaces
176*4b22b933Srs200217
177*4b22b933Srs200217 Revision 1.495 2004/12/16 21:27:37 ksekar
178*4b22b933Srs200217 Fixed build failures when compiled with verbose debugging messages
179*4b22b933Srs200217
180*4b22b933Srs200217 Revision 1.494 2004/12/16 20:46:56 cheshire
181*4b22b933Srs200217 Fix compiler warnings
182*4b22b933Srs200217
183*4b22b933Srs200217 Revision 1.493 2004/12/16 20:13:00 cheshire
184*4b22b933Srs200217 <rdar://problem/3324626> Cache memory management improvements
185*4b22b933Srs200217
186*4b22b933Srs200217 Revision 1.492 2004/12/16 08:03:24 shersche
187*4b22b933Srs200217 Fix compilation error when UNICAST_DISABLED is set
188*4b22b933Srs200217
189*4b22b933Srs200217 Revision 1.491 2004/12/11 01:52:11 cheshire
190*4b22b933Srs200217 <rdar://problem/3785820> Support kDNSServiceFlagsAllowRemoteQuery for registering services too
191*4b22b933Srs200217
192*4b22b933Srs200217 Revision 1.490 2004/12/10 20:06:25 cheshire
193*4b22b933Srs200217 <rdar://problem/3915074> Reduce egregious stack space usage
194*4b22b933Srs200217 Reduced SendDelayedUnicastResponse() stack frame from 9K to 112 bytes
195*4b22b933Srs200217
196*4b22b933Srs200217 Revision 1.489 2004/12/10 20:03:43 cheshire
197*4b22b933Srs200217 <rdar://problem/3915074> Reduce egregious stack space usage
198*4b22b933Srs200217 Reduced mDNSCoreReceiveQuery() stack frame from 9K to 144 bytes
199*4b22b933Srs200217
200*4b22b933Srs200217 Revision 1.488 2004/12/10 19:50:41 cheshire
201*4b22b933Srs200217 <rdar://problem/3915074> Reduce egregious stack space usage
202*4b22b933Srs200217 Reduced SendResponses() stack frame from 9K to 176 bytes
203*4b22b933Srs200217
204*4b22b933Srs200217 Revision 1.487 2004/12/10 19:39:13 cheshire
205*4b22b933Srs200217 <rdar://problem/3915074> Reduce egregious stack space usage
206*4b22b933Srs200217 Reduced SendQueries() stack frame from 18K to 112 bytes
207*4b22b933Srs200217
208*4b22b933Srs200217 Revision 1.486 2004/12/10 14:16:17 cheshire
209*4b22b933Srs200217 <rdar://problem/3889788> Relax update rate limiting
210*4b22b933Srs200217 We now allow an average rate of ten updates per minute.
211*4b22b933Srs200217 Updates in excess of that are rate limited, but more gently than before.
212*4b22b933Srs200217
213*4b22b933Srs200217 Revision 1.485 2004/12/10 02:09:24 cheshire
214*4b22b933Srs200217 <rdar://problem/3898376> Modify default TTLs
215*4b22b933Srs200217
216*4b22b933Srs200217 Revision 1.484 2004/12/09 03:15:40 ksekar
217*4b22b933Srs200217 <rdar://problem/3806610> use _legacy instead of _default to find "empty string" browse domains
218*4b22b933Srs200217
219*4b22b933Srs200217 Revision 1.483 2004/12/07 23:00:14 ksekar
220*4b22b933Srs200217 <rdar://problem/3908336> DNSServiceRegisterRecord() can crash on deregistration:
221*4b22b933Srs200217 Call RecordProbeFailure even if there is no record callback
222*4b22b933Srs200217
223*4b22b933Srs200217 Revision 1.482 2004/12/07 22:49:06 cheshire
224*4b22b933Srs200217 <rdar://problem/3908850> BIND doesn't allow zero-length TXT records
225*4b22b933Srs200217
226*4b22b933Srs200217 Revision 1.481 2004/12/07 21:26:04 ksekar
227*4b22b933Srs200217 <rdar://problem/3908336> DNSServiceRegisterRecord() can crash on deregistration
228*4b22b933Srs200217
229*4b22b933Srs200217 Revision 1.480 2004/12/07 20:42:33 cheshire
230*4b22b933Srs200217 Add explicit context parameter to mDNS_RemoveRecordFromService()
231*4b22b933Srs200217
232*4b22b933Srs200217 Revision 1.479 2004/12/07 17:50:49 ksekar
233*4b22b933Srs200217 <rdar://problem/3908850> BIND doesn't allow zero-length TXT records
234*4b22b933Srs200217
235*4b22b933Srs200217 Revision 1.478 2004/12/06 21:15:22 ksekar
236*4b22b933Srs200217 <rdar://problem/3884386> mDNSResponder crashed in CheckServiceRegistrations
237*4b22b933Srs200217
238*4b22b933Srs200217 Revision 1.477 2004/12/04 02:12:45 cheshire
239*4b22b933Srs200217 <rdar://problem/3517236> mDNSResponder puts LargeCacheRecord on the stack
240*4b22b933Srs200217
241*4b22b933Srs200217 Revision 1.476 2004/11/29 23:34:31 cheshire
242*4b22b933Srs200217 On platforms with coarse time resolutions, ORing time values with one to ensure they are non-zero
243*4b22b933Srs200217 is crude, and effectively halves the time resolution. The more selective NonZeroTime() function
244*4b22b933Srs200217 only nudges the time value to 1 if the interval calculation happens to result in the value zero.
245*4b22b933Srs200217
246*4b22b933Srs200217 Revision 1.475 2004/11/29 23:13:31 cheshire
247*4b22b933Srs200217 <rdar://problem/3484552> All unique records in a set should have the cache flush bit set
248*4b22b933Srs200217 Additional check: Make sure we don't unnecessarily send packets containing only additionals.
249*4b22b933Srs200217 (This could occur with multi-packet KA lists, if the answer and additionals were marked
250*4b22b933Srs200217 by the query packet, and then the answer were later suppressed in a subsequent KA packet.)
251*4b22b933Srs200217
252*4b22b933Srs200217 Revision 1.474 2004/11/29 17:18:12 cheshire
253*4b22b933Srs200217 Remove "Unknown DNS packet type" message for update responses
254*4b22b933Srs200217
255*4b22b933Srs200217 Revision 1.473 2004/11/25 01:57:52 cheshire
256*4b22b933Srs200217 <rdar://problem/3484552> All unique records in a set should have the cache flush bit set
257*4b22b933Srs200217
258*4b22b933Srs200217 Revision 1.472 2004/11/25 01:28:09 cheshire
259*4b22b933Srs200217 <rdar://problem/3557050> Need to implement random delay for 'QU' unicast replies (and set cache flush bit too)
260*4b22b933Srs200217
261*4b22b933Srs200217 Revision 1.471 2004/11/25 01:10:13 cheshire
262*4b22b933Srs200217 Move code to add additional records to a subroutine called AddAdditionalsToResponseList()
263*4b22b933Srs200217
264*4b22b933Srs200217 Revision 1.470 2004/11/24 21:54:44 cheshire
265*4b22b933Srs200217 <rdar://problem/3894475> mDNSCore not receiving unicast responses properly
266*4b22b933Srs200217
267*4b22b933Srs200217 Revision 1.469 2004/11/24 04:50:39 cheshire
268*4b22b933Srs200217 Minor tidying
269*4b22b933Srs200217
270*4b22b933Srs200217 Revision 1.468 2004/11/24 01:47:07 cheshire
271*4b22b933Srs200217 <rdar://problem/3780207> DNSServiceRegisterRecord should call CallBack on success.
272*4b22b933Srs200217
273*4b22b933Srs200217 Revision 1.467 2004/11/24 01:41:28 cheshire
274*4b22b933Srs200217 Rename CompleteProbing() to AcknowledgeRecord()
275*4b22b933Srs200217
276*4b22b933Srs200217 Revision 1.466 2004/11/23 21:08:07 ksekar
277*4b22b933Srs200217 Don't use ID to demux multicast/unicast now that unicast uses random IDs
278*4b22b933Srs200217
279*4b22b933Srs200217 Revision 1.465 2004/11/15 20:09:21 ksekar
280*4b22b933Srs200217 <rdar://problem/3719050> Wide Area support for Add/Remove record
281*4b22b933Srs200217
282*4b22b933Srs200217 Revision 1.464 2004/11/03 01:44:36 cheshire
283*4b22b933Srs200217 Update debugging messages
284*4b22b933Srs200217
285*4b22b933Srs200217 Revision 1.463 2004/10/29 02:38:48 cheshire
286*4b22b933Srs200217 Fix Windows compile errors
287*4b22b933Srs200217
288*4b22b933Srs200217 Revision 1.462 2004/10/28 19:21:07 cheshire
289*4b22b933Srs200217 Guard against registering interface with zero InterfaceID
290*4b22b933Srs200217
291*4b22b933Srs200217 Revision 1.461 2004/10/28 19:02:16 cheshire
292*4b22b933Srs200217 Remove \n from LogMsg() call
293*4b22b933Srs200217
294*4b22b933Srs200217 Revision 1.460 2004/10/28 03:24:40 cheshire
295*4b22b933Srs200217 Rename m->CanReceiveUnicastOn as m->CanReceiveUnicastOn5353
296*4b22b933Srs200217
297*4b22b933Srs200217 Revision 1.459 2004/10/26 22:34:37 cheshire
298*4b22b933Srs200217 <rdar://problem/3468995> Need to protect mDNSResponder from unbounded packet flooding
299*4b22b933Srs200217
300*4b22b933Srs200217 Revision 1.458 2004/10/26 20:45:28 cheshire
301*4b22b933Srs200217 Show mask in "invalid mask" message
302*4b22b933Srs200217
303*4b22b933Srs200217 Revision 1.457 2004/10/26 06:28:36 cheshire
304*4b22b933Srs200217 Now that we don't check IP TTL any more, remove associated log message
305*4b22b933Srs200217
306*4b22b933Srs200217 Revision 1.456 2004/10/26 06:21:42 cheshire
307*4b22b933Srs200217 Adjust mask validity check to allow an all-ones mask (for IPv6 ::1 loopback address)
308*4b22b933Srs200217
309*4b22b933Srs200217 Revision 1.455 2004/10/26 06:11:40 cheshire
310*4b22b933Srs200217 Add improved logging to aid in diagnosis of <rdar://problem/3842714> mDNSResponder crashed
311*4b22b933Srs200217
312*4b22b933Srs200217 Revision 1.454 2004/10/23 01:16:00 cheshire
313*4b22b933Srs200217 <rdar://problem/3851677> uDNS operations not always reliable on multi-homed hosts
314*4b22b933Srs200217
315*4b22b933Srs200217 Revision 1.453 2004/10/22 20:52:06 ksekar
316*4b22b933Srs200217 <rdar://problem/3799260> Create NAT port mappings for Long Lived Queries
317*4b22b933Srs200217
318*4b22b933Srs200217 Revision 1.452 2004/10/20 01:50:40 cheshire
319*4b22b933Srs200217 <rdar://problem/3844991> Cannot resolve non-local registrations using the mach API
320*4b22b933Srs200217 Implemented ForceMCast mode for AuthRecords as well as for Questions
321*4b22b933Srs200217
322*4b22b933Srs200217 Revision 1.451 2004/10/19 21:33:15 cheshire
323*4b22b933Srs200217 <rdar://problem/3844991> Cannot resolve non-local registrations using the mach API
324*4b22b933Srs200217 Added flag 'kDNSServiceFlagsForceMulticast'. Passing through an interface id for a unicast name
325*4b22b933Srs200217 doesn't force multicast unless you set this flag to indicate explicitly that this is what you want
326*4b22b933Srs200217
327*4b22b933Srs200217 Revision 1.450 2004/10/19 17:42:59 ksekar
328*4b22b933Srs200217 Fixed compiler warnings for non-debug builds.
329*4b22b933Srs200217
330*4b22b933Srs200217 Revision 1.449 2004/10/18 22:57:07 cheshire
331*4b22b933Srs200217 <rdar://problem/3711302> Seen in console: Ignored apparent spoof mDNS Response with TTL 1
332*4b22b933Srs200217
333*4b22b933Srs200217 Revision 1.448 2004/10/16 00:16:59 cheshire
334*4b22b933Srs200217 <rdar://problem/3770558> Replace IP TTL 255 check with local subnet source address check
335*4b22b933Srs200217
336*4b22b933Srs200217 Revision 1.447 2004/10/15 00:51:21 cheshire
337*4b22b933Srs200217 <rdar://problem/3711302> Seen in console: Ignored apparent spoof mDNS Response with TTL 1
338*4b22b933Srs200217
339*4b22b933Srs200217 Revision 1.446 2004/10/14 00:43:34 cheshire
340*4b22b933Srs200217 <rdar://problem/3815984> Services continue to announce SRV and HINFO
341*4b22b933Srs200217
342*4b22b933Srs200217 Revision 1.445 2004/10/12 21:07:09 cheshire
343*4b22b933Srs200217 Set up m->p in mDNS_Init() before calling mDNSPlatformTimeInit()
344*4b22b933Srs200217
345*4b22b933Srs200217 Revision 1.444 2004/10/11 17:54:16 ksekar
346*4b22b933Srs200217 Changed hashtable pointer output from debugf to verbosedebugf.
347*4b22b933Srs200217
348*4b22b933Srs200217 Revision 1.443 2004/10/10 07:05:45 cheshire
349*4b22b933Srs200217 For consistency, use symbol "localdomain" instead of literal string
350*4b22b933Srs200217
351*4b22b933Srs200217 Revision 1.442 2004/10/08 20:25:10 cheshire
352*4b22b933Srs200217 Change of plan for <rdar://problem/3831716> -- we're not going to do that at this time
353*4b22b933Srs200217
354*4b22b933Srs200217 Revision 1.441 2004/10/08 03:25:01 ksekar
355*4b22b933Srs200217 <rdar://problem/3831716> domain enumeration should use LLQs
356*4b22b933Srs200217
357*4b22b933Srs200217 Revision 1.440 2004/10/06 01:44:19 cheshire
358*4b22b933Srs200217 <rdar://problem/3813936> Resolving too quickly sometimes returns stale TXT record
359*4b22b933Srs200217
360*4b22b933Srs200217 Revision 1.439 2004/10/03 23:14:11 cheshire
361*4b22b933Srs200217 Add "mDNSEthAddr" type and "zeroEthAddr" constant
362*4b22b933Srs200217
363*4b22b933Srs200217 Revision 1.438 2004/09/29 23:07:04 cheshire
364*4b22b933Srs200217 Patch from Pavel Repin to fix compile error on Windows
365*4b22b933Srs200217
366*4b22b933Srs200217 Revision 1.437 2004/09/28 02:23:50 cheshire
367*4b22b933Srs200217 <rdar://problem/3637266> Deliver near-pending "remove" events before new "add" events
368*4b22b933Srs200217 Don't need to search the entire cache for nearly-expired records -- just the appropriate hash slot
369*4b22b933Srs200217 For records with the cache flush bit set, defer the decision until the end of the packet
370*4b22b933Srs200217
371*4b22b933Srs200217 Revision 1.436 2004/09/28 01:27:04 cheshire
372*4b22b933Srs200217 Update incorrect log message
373*4b22b933Srs200217
374*4b22b933Srs200217 Revision 1.435 2004/09/25 02:41:39 cheshire
375*4b22b933Srs200217 <rdar://problem/3637266> Deliver near-pending "remove" events before new "add" events
376*4b22b933Srs200217
377*4b22b933Srs200217 Revision 1.434 2004/09/25 02:32:06 cheshire
378*4b22b933Srs200217 Update comments
379*4b22b933Srs200217
380*4b22b933Srs200217 Revision 1.433 2004/09/25 02:24:27 cheshire
381*4b22b933Srs200217 Removed unused rr->UseCount
382*4b22b933Srs200217
383*4b22b933Srs200217 Revision 1.432 2004/09/24 21:35:17 cheshire
384*4b22b933Srs200217 <rdar://problem/3561220> Browses are no longer piggybacking on other browses
385*4b22b933Srs200217 TargetPort and TargetQID are allowed to be undefined if no question->Target is set
386*4b22b933Srs200217
387*4b22b933Srs200217 Revision 1.431 2004/09/24 21:33:12 cheshire
388*4b22b933Srs200217 Adjust comment
389*4b22b933Srs200217
390*4b22b933Srs200217 Revision 1.430 2004/09/24 02:15:49 cheshire
391*4b22b933Srs200217 <rdar://problem/3680865> Late conflicts don't send goodbye packets on other interfaces
392*4b22b933Srs200217
393*4b22b933Srs200217 Revision 1.429 2004/09/24 00:20:21 cheshire
394*4b22b933Srs200217 <rdar://problem/3483349> Any rrtype is a conflict for unique records
395*4b22b933Srs200217
396*4b22b933Srs200217 Revision 1.428 2004/09/24 00:12:25 cheshire
397*4b22b933Srs200217 Get rid of unused RRUniqueOrKnownUnique(RR)
398*4b22b933Srs200217
399*4b22b933Srs200217 Revision 1.427 2004/09/23 20:44:11 cheshire
400*4b22b933Srs200217 <rdar://problem/3813148> Reduce timeout before expiring records on failure
401*4b22b933Srs200217
402*4b22b933Srs200217 Revision 1.426 2004/09/23 20:21:07 cheshire
403*4b22b933Srs200217 <rdar://problem/3426876> Refine "immediate answer burst; restarting exponential backoff sequence" logic
404*4b22b933Srs200217 Associate a unique sequence number with each received packet, and only increment the count of recent answer
405*4b22b933Srs200217 packets if the packet sequence number for this answer record is not one we've already seen and counted.
406*4b22b933Srs200217
407*4b22b933Srs200217 Revision 1.425 2004/09/23 20:14:38 cheshire
408*4b22b933Srs200217 Rename "question->RecentAnswers" to "question->RecentAnswerPkts"
409*4b22b933Srs200217
410*4b22b933Srs200217 Revision 1.424 2004/09/23 00:58:36 cheshire
411*4b22b933Srs200217 <rdar://problem/3781269> Rate limiting interferes with updating TXT records
412*4b22b933Srs200217
413*4b22b933Srs200217 Revision 1.423 2004/09/23 00:50:53 cheshire
414*4b22b933Srs200217 <rdar://problem/3419452> Don't send a (DE) if a service is unregistered after wake from sleep
415*4b22b933Srs200217
416*4b22b933Srs200217 Revision 1.422 2004/09/22 02:34:46 cheshire
417*4b22b933Srs200217 Move definitions of default TTL times from mDNS.c to mDNSEmbeddedAPI.h
418*4b22b933Srs200217
419*4b22b933Srs200217 Revision 1.421 2004/09/21 23:29:49 cheshire
420*4b22b933Srs200217 <rdar://problem/3680045> DNSServiceResolve should delay sending packets
421*4b22b933Srs200217
422*4b22b933Srs200217 Revision 1.420 2004/09/21 23:01:42 cheshire
423*4b22b933Srs200217 Update debugf messages
424*4b22b933Srs200217
425*4b22b933Srs200217 Revision 1.419 2004/09/21 19:51:14 cheshire
426*4b22b933Srs200217 Move "Starting time value" message from mDNS.c to mDNSMacOSX/daemon.c
427*4b22b933Srs200217
428*4b22b933Srs200217 Revision 1.418 2004/09/21 18:40:17 cheshire
429*4b22b933Srs200217 <rdar://problem/3376752> Adjust default record TTLs
430*4b22b933Srs200217
431*4b22b933Srs200217 Revision 1.417 2004/09/21 17:32:16 cheshire
432*4b22b933Srs200217 <rdar://problem/3809484> Rate limiting imposed too soon
433*4b22b933Srs200217
434*4b22b933Srs200217 Revision 1.416 2004/09/20 23:52:01 cheshire
435*4b22b933Srs200217 CFSocket{Puma}.c renamed to mDNSMacOSX{Puma}.c
436*4b22b933Srs200217
437*4b22b933Srs200217 Revision 1.415 2004/09/18 01:14:09 cheshire
438*4b22b933Srs200217 <rdar://problem/3485375> Resolve() should not bother doing AAAA queries on machines with no IPv6 interfaces
439*4b22b933Srs200217
440*4b22b933Srs200217 Revision 1.414 2004/09/18 01:06:48 cheshire
441*4b22b933Srs200217 Add comments
442*4b22b933Srs200217
443*4b22b933Srs200217 Revision 1.413 2004/09/17 01:08:48 cheshire
444*4b22b933Srs200217 Renamed mDNSClientAPI.h to mDNSEmbeddedAPI.h
445*4b22b933Srs200217 The name "mDNSClientAPI.h" is misleading to new developers looking at this code. The interfaces
446*4b22b933Srs200217 declared in that file are ONLY appropriate to single-address-space embedded applications.
447*4b22b933Srs200217 For clients on general-purpose computers, the interfaces defined in dns_sd.h should be used.
448*4b22b933Srs200217
449*4b22b933Srs200217 Revision 1.412 2004/09/17 00:46:33 cheshire
450*4b22b933Srs200217 mDNS_TimeNow should take const mDNS parameter
451*4b22b933Srs200217
452*4b22b933Srs200217 Revision 1.411 2004/09/17 00:31:51 cheshire
453*4b22b933Srs200217 For consistency with ipv6, renamed rdata field 'ip' to 'ipv4'
454*4b22b933Srs200217
455*4b22b933Srs200217 Revision 1.410 2004/09/17 00:19:10 cheshire
456*4b22b933Srs200217 For consistency with AllDNSLinkGroupv6, rename AllDNSLinkGroup to AllDNSLinkGroupv4
457*4b22b933Srs200217
458*4b22b933Srs200217 Revision 1.409 2004/09/16 21:59:15 cheshire
459*4b22b933Srs200217 For consistency with zerov6Addr, rename zeroIPAddr to zerov4Addr
460*4b22b933Srs200217
461*4b22b933Srs200217 Revision 1.408 2004/09/16 21:36:36 cheshire
462*4b22b933Srs200217 <rdar://problem/3803162> Fix unsafe use of mDNSPlatformTimeNow()
463*4b22b933Srs200217 Changes to add necessary locking calls around unicast DNS operations
464*4b22b933Srs200217
465*4b22b933Srs200217 Revision 1.407 2004/09/16 02:29:39 cheshire
466*4b22b933Srs200217 Moved mDNS_Lock/mDNS_Unlock to DNSCommon.c; Added necessary locking around
467*4b22b933Srs200217 uDNS_ReceiveMsg, uDNS_StartQuery, uDNS_UpdateRecord, uDNS_RegisterService
468*4b22b933Srs200217
469*4b22b933Srs200217 Revision 1.406 2004/09/16 01:58:14 cheshire
470*4b22b933Srs200217 Fix compiler warnings
471*4b22b933Srs200217
472*4b22b933Srs200217 Revision 1.405 2004/09/16 00:24:48 cheshire
473*4b22b933Srs200217 <rdar://problem/3803162> Fix unsafe use of mDNSPlatformTimeNow()
474*4b22b933Srs200217
475*4b22b933Srs200217 Revision 1.404 2004/09/15 21:44:11 cheshire
476*4b22b933Srs200217 <rdar://problem/3681031> Randomize initial timenow_adjust value in mDNS_Init
477*4b22b933Srs200217 Show time value in log to help diagnose errors
478*4b22b933Srs200217
479*4b22b933Srs200217 Revision 1.403 2004/09/15 00:46:32 ksekar
480*4b22b933Srs200217 Changed debugf to verbosedebugf in CheckCacheExpiration
481*4b22b933Srs200217
482*4b22b933Srs200217 Revision 1.402 2004/09/14 23:59:55 cheshire
483*4b22b933Srs200217 <rdar://problem/3681031> Randomize initial timenow_adjust value in mDNS_Init
484*4b22b933Srs200217
485*4b22b933Srs200217 Revision 1.401 2004/09/14 23:27:46 cheshire
486*4b22b933Srs200217 Fix compile errors
487*4b22b933Srs200217
488*4b22b933Srs200217 Revision 1.400 2004/09/02 03:48:47 cheshire
489*4b22b933Srs200217 <rdar://problem/3709039> Disable targeted unicast query support by default
490*4b22b933Srs200217 1. New flag kDNSServiceFlagsAllowRemoteQuery to indicate we want to allow remote queries for this record
491*4b22b933Srs200217 2. New field AllowRemoteQuery in AuthRecord structure
492*4b22b933Srs200217 3. uds_daemon.c sets AllowRemoteQuery if kDNSServiceFlagsAllowRemoteQuery is set
493*4b22b933Srs200217 4. mDNS.c only answers remote queries if AllowRemoteQuery is set
494*4b22b933Srs200217
495*4b22b933Srs200217 Revision 1.399 2004/09/02 01:39:40 cheshire
496*4b22b933Srs200217 For better readability, follow consistent convention that QR bit comes first, followed by OP bits
497*4b22b933Srs200217
498*4b22b933Srs200217 Revision 1.398 2004/09/01 03:59:29 ksekar
499*4b22b933Srs200217 <rdar://problem/3783453>: Conditionally compile out uDNS code on Windows
500*4b22b933Srs200217
501*4b22b933Srs200217 Revision 1.397 2004/08/25 22:04:25 rpantos
502*4b22b933Srs200217 Fix the standard Windows compile error.
503*4b22b933Srs200217
504*4b22b933Srs200217 Revision 1.396 2004/08/25 00:37:27 ksekar
505*4b22b933Srs200217 <rdar://problem/3774635>: Cleanup DynDNS hostname registration code
506*4b22b933Srs200217
507*4b22b933Srs200217 Revision 1.395 2004/08/18 17:21:18 ksekar
508*4b22b933Srs200217 Removed double-call of uDNS_AdvertiseInterface from mDNS_SetFQDNs()
509*4b22b933Srs200217
510*4b22b933Srs200217 Revision 1.394 2004/08/14 03:22:41 cheshire
511*4b22b933Srs200217 <rdar://problem/3762579> Dynamic DNS UI <-> mDNSResponder glue
512*4b22b933Srs200217 Add GetUserSpecifiedDDNSName() routine
513*4b22b933Srs200217 Convert ServiceRegDomain to domainname instead of C string
514*4b22b933Srs200217 Replace mDNS_GenerateFQDN/mDNS_GenerateGlobalFQDN with mDNS_SetFQDNs
515*4b22b933Srs200217
516*4b22b933Srs200217 Revision 1.393 2004/08/13 23:42:52 cheshire
517*4b22b933Srs200217 Removed unused "zeroDomainNamePtr"
518*4b22b933Srs200217
519*4b22b933Srs200217 Revision 1.392 2004/08/13 23:37:02 cheshire
520*4b22b933Srs200217 Now that we do both uDNS and mDNS, global replace "uDNS_info.hostname" with
521*4b22b933Srs200217 "uDNS_info.UnicastHostname" for clarity
522*4b22b933Srs200217
523*4b22b933Srs200217 Revision 1.391 2004/08/13 23:25:00 cheshire
524*4b22b933Srs200217 Now that we do both uDNS and mDNS, global replace "m->hostname" with
525*4b22b933Srs200217 "m->MulticastHostname" for clarity
526*4b22b933Srs200217
527*4b22b933Srs200217 Revision 1.390 2004/08/11 02:17:01 cheshire
528*4b22b933Srs200217 <rdar://problem/3514236> Registering service with port number 0 should create a "No Such Service" record
529*4b22b933Srs200217
530*4b22b933Srs200217 Revision 1.389 2004/08/10 23:19:14 ksekar
531*4b22b933Srs200217 <rdar://problem/3722542>: DNS Extension daemon for Wide Area Service Discovery
532*4b22b933Srs200217 Moved routines/constants to allow extern access for garbage collection daemon
533*4b22b933Srs200217
534*4b22b933Srs200217 Revision 1.388 2004/07/30 17:40:06 ksekar
535*4b22b933Srs200217 <rdar://problem/3739115>: TXT Record updates not available for wide-area services
536*4b22b933Srs200217
537*4b22b933Srs200217 Revision 1.387 2004/07/26 22:49:30 ksekar
538*4b22b933Srs200217 <rdar://problem/3651409>: Feature #9516: Need support for NATPMP in client
539*4b22b933Srs200217
540*4b22b933Srs200217 Revision 1.386 2004/07/13 21:24:24 rpantos
541*4b22b933Srs200217 Fix for <rdar://problem/3701120>.
542*4b22b933Srs200217
543*4b22b933Srs200217 Revision 1.385 2004/06/18 19:09:59 cheshire
544*4b22b933Srs200217 <rdar://problem/3588761> Current method of doing subtypes causes name collisions
545*4b22b933Srs200217
546*4b22b933Srs200217 Revision 1.384 2004/06/15 04:31:23 cheshire
547*4b22b933Srs200217 Make sure to clear m->CurrentRecord at the end of AnswerNewLocalOnlyQuestion()
548*4b22b933Srs200217
549*4b22b933Srs200217 Revision 1.383 2004/06/11 00:04:59 cheshire
550*4b22b933Srs200217 <rdar://problem/3595602> TTL must be greater than zero for DNSServiceRegisterRecord
551*4b22b933Srs200217
552*4b22b933Srs200217 Revision 1.382 2004/06/08 04:59:40 cheshire
553*4b22b933Srs200217 Tidy up wording -- log messages are already prefixed with "mDNSResponder", so don't need to repeat it
554*4b22b933Srs200217
555*4b22b933Srs200217 Revision 1.381 2004/06/05 00:57:30 cheshire
556*4b22b933Srs200217 Remove incorrect LogMsg()
557*4b22b933Srs200217
558*4b22b933Srs200217 Revision 1.380 2004/06/05 00:04:26 cheshire
559*4b22b933Srs200217 <rdar://problem/3668639>: wide-area domains should be returned in reg. domain enumeration
560*4b22b933Srs200217
561*4b22b933Srs200217 Revision 1.379 2004/05/28 23:42:36 ksekar
562*4b22b933Srs200217 <rdar://problem/3258021>: Feature: DNS server->client notification on record changes (#7805)
563*4b22b933Srs200217
564*4b22b933Srs200217 Revision 1.378 2004/05/25 17:25:25 cheshire
565*4b22b933Srs200217 Remove extraneous blank lines and white space
566*4b22b933Srs200217
567*4b22b933Srs200217 Revision 1.377 2004/05/18 23:51:25 cheshire
568*4b22b933Srs200217 Tidy up all checkin comments to use consistent "<rdar://problem/xxxxxxx>" format for bug numbers
569*4b22b933Srs200217
570*4b22b933Srs200217 Revision 1.376 2004/05/05 18:30:44 ksekar
571*4b22b933Srs200217 Restored surpressed Cache Tail debug messages.
572*4b22b933Srs200217
573*4b22b933Srs200217 Revision 1.375 2004/04/26 21:36:25 cheshire
574*4b22b933Srs200217 Only send IPv4 (or v6) multicast when IPv4 (or v6) multicast send/receive
575*4b22b933Srs200217 is indicated as being available on that interface
576*4b22b933Srs200217
577*4b22b933Srs200217 Revision 1.374 2004/04/21 02:53:26 cheshire
578*4b22b933Srs200217 Typo in debugf statement
579*4b22b933Srs200217
580*4b22b933Srs200217 Revision 1.373 2004/04/21 02:49:11 cheshire
581*4b22b933Srs200217 To reduce future confusion, renamed 'TxAndRx' to 'McastTxRx'
582*4b22b933Srs200217
583*4b22b933Srs200217 Revision 1.372 2004/04/21 02:38:51 cheshire
584*4b22b933Srs200217 Add debugging checks
585*4b22b933Srs200217
586*4b22b933Srs200217 Revision 1.371 2004/04/14 23:09:28 ksekar
587*4b22b933Srs200217 Support for TSIG signed dynamic updates.
588*4b22b933Srs200217
589*4b22b933Srs200217 Revision 1.370 2004/04/09 17:40:26 cheshire
590*4b22b933Srs200217 Remove unnecessary "Multicast" field -- it duplicates the semantics of the existing McastTxRx field
591*4b22b933Srs200217
592*4b22b933Srs200217 Revision 1.369 2004/04/09 16:34:00 cheshire
593*4b22b933Srs200217 Debugging code for later; currently unused
594*4b22b933Srs200217
595*4b22b933Srs200217 Revision 1.368 2004/04/02 19:19:48 cheshire
596*4b22b933Srs200217 Add code to do optional logging of multi-packet KA list time intervals
597*4b22b933Srs200217
598*4b22b933Srs200217 Revision 1.367 2004/03/20 03:16:10 cheshire
599*4b22b933Srs200217 Minor refinement to "Excessive update rate" message
600*4b22b933Srs200217
601*4b22b933Srs200217 Revision 1.366 2004/03/20 03:12:57 cheshire
602*4b22b933Srs200217 <rdar://problem/3587619>: UpdateCredits not granted promptly enough
603*4b22b933Srs200217
604*4b22b933Srs200217 Revision 1.365 2004/03/19 23:51:22 cheshire
605*4b22b933Srs200217 Change to use symbolic constant kUpdateCreditRefreshInterval instead of (mDNSPlatformOneSecond * 60)
606*4b22b933Srs200217
607*4b22b933Srs200217 Revision 1.364 2004/03/13 01:57:33 ksekar
608*4b22b933Srs200217 <rdar://problem/3192546>: DynDNS: Dynamic update of service records
609*4b22b933Srs200217
610*4b22b933Srs200217 Revision 1.363 2004/03/12 21:00:51 cheshire
611*4b22b933Srs200217 Also show port numbers when logging "apparent spoof mDNS Response" messages
612*4b22b933Srs200217
613*4b22b933Srs200217 Revision 1.362 2004/03/12 08:58:18 cheshire
614*4b22b933Srs200217 Guard against empty TXT records
615*4b22b933Srs200217
616*4b22b933Srs200217 Revision 1.361 2004/03/09 03:00:46 cheshire
617*4b22b933Srs200217 <rdar://problem/3581961> Don't take lock until after mDNS_Update() has validated that the data is good.
618*4b22b933Srs200217
619*4b22b933Srs200217 Revision 1.360 2004/03/08 02:52:41 cheshire
620*4b22b933Srs200217 Minor debugging fix: Make sure 'target' is initialized so we don't crash writing debugging log messages
621*4b22b933Srs200217
622*4b22b933Srs200217 Revision 1.359 2004/03/02 03:21:56 cheshire
623*4b22b933Srs200217 <rdar://problem/3549576> Properly support "_services._dns-sd._udp" meta-queries
624*4b22b933Srs200217
625*4b22b933Srs200217 Revision 1.358 2004/02/20 08:18:34 cheshire
626*4b22b933Srs200217 <rdar://problem/3564799>: mDNSResponder sometimes announces AAAA records unnecessarily
627*4b22b933Srs200217
628*4b22b933Srs200217 Revision 1.357 2004/02/18 01:47:41 cheshire
629*4b22b933Srs200217 <rdar://problem/3553472>: Insufficient delay waiting for multi-packet KA lists causes AirPort traffic storms
630*4b22b933Srs200217
631*4b22b933Srs200217 Revision 1.356 2004/02/06 23:04:19 ksekar
632*4b22b933Srs200217 Basic Dynamic Update support via mDNS_Register (dissabled via
633*4b22b933Srs200217 UNICAST_REGISTRATION #define)
634*4b22b933Srs200217
635*4b22b933Srs200217 Revision 1.355 2004/02/05 09:32:33 cheshire
636*4b22b933Srs200217 Fix from Bob Bradley: When using the "%.*s" string form,
637*4b22b933Srs200217 guard against truncating in the middle of a multi-byte UTF-8 character.
638*4b22b933Srs200217
639*4b22b933Srs200217 Revision 1.354 2004/02/05 09:30:22 cheshire
640*4b22b933Srs200217 Update comments
641*4b22b933Srs200217
642*4b22b933Srs200217 Revision 1.353 2004/01/28 03:41:00 cheshire
643*4b22b933Srs200217 <rdar://problem/3541946>: Need ability to do targeted queries as well as multicast queries
644*4b22b933Srs200217
645*4b22b933Srs200217 Revision 1.352 2004/01/28 02:30:07 ksekar
646*4b22b933Srs200217 Added default Search Domains to unicast browsing, controlled via
647*4b22b933Srs200217 Networking sharing prefs pane. Stopped sending unicast messages on
648*4b22b933Srs200217 every interface. Fixed unicast resolving via mach-port API.
649*4b22b933Srs200217
650*4b22b933Srs200217 Revision 1.351 2004/01/27 20:15:22 cheshire
651*4b22b933Srs200217 <rdar://problem/3541288>: Time to prune obsolete code for listening on port 53
652*4b22b933Srs200217
653*4b22b933Srs200217 Revision 1.350 2004/01/24 23:38:16 cheshire
654*4b22b933Srs200217 Use mDNSVal16() instead of shifting and ORing operations
655*4b22b933Srs200217
656*4b22b933Srs200217 Revision 1.349 2004/01/23 23:23:14 ksekar
657*4b22b933Srs200217 Added TCP support for truncated unicast messages.
658*4b22b933Srs200217
659*4b22b933Srs200217 Revision 1.348 2004/01/22 03:54:11 cheshire
660*4b22b933Srs200217 Create special meta-interface 'mDNSInterface_ForceMCast' (-2),
661*4b22b933Srs200217 which means "do this query via multicast, even if it's apparently a unicast domain"
662*4b22b933Srs200217
663*4b22b933Srs200217 Revision 1.347 2004/01/22 03:50:49 cheshire
664*4b22b933Srs200217 If the client has specified an explicit InterfaceID, then do query by multicast, not unicast
665*4b22b933Srs200217
666*4b22b933Srs200217 Revision 1.346 2004/01/22 03:48:41 cheshire
667*4b22b933Srs200217 Make sure uDNS client doesn't accidentally use query ID zero
668*4b22b933Srs200217
669*4b22b933Srs200217 Revision 1.345 2004/01/22 03:43:08 cheshire
670*4b22b933Srs200217 Export constants like mDNSInterface_LocalOnly so that the client layers can use them
671*4b22b933Srs200217
672*4b22b933Srs200217 Revision 1.344 2004/01/21 21:53:18 cheshire
673*4b22b933Srs200217 <rdar://problem/3448144>: Don't try to receive unicast responses if we're not the first to bind to the UDP port
674*4b22b933Srs200217
675*4b22b933Srs200217 Revision 1.343 2003/12/23 00:07:47 cheshire
676*4b22b933Srs200217 Make port number in debug message be five-character field, left justified
677*4b22b933Srs200217
678*4b22b933Srs200217 Revision 1.342 2003/12/20 01:34:28 cheshire
679*4b22b933Srs200217 <rdar://problem/3515876>: Error putting additional records into packets
680*4b22b933Srs200217 Another fix from Rampi: responseptr needs to be updated inside the "for" loop,
681*4b22b933Srs200217 after every record, not once at the end.
682*4b22b933Srs200217
683*4b22b933Srs200217 Revision 1.341 2003/12/18 22:56:12 cheshire
684*4b22b933Srs200217 <rdar://problem/3510798>: Reduce syslog messages about ignored spoof packets
685*4b22b933Srs200217
686*4b22b933Srs200217 Revision 1.340 2003/12/16 02:31:37 cheshire
687*4b22b933Srs200217 Minor update to comments
688*4b22b933Srs200217
689*4b22b933Srs200217 Revision 1.339 2003/12/13 05:50:33 bradley
690*4b22b933Srs200217 Fixed crash with mDNS_Lock/Unlock being called for the initial GrowCache before the platform
691*4b22b933Srs200217 layer has been initialized. Protect mDNS_reentrancy when completing the core initialization to
692*4b22b933Srs200217 fix a race condition during async initialization. Fixed buffer overrun for 1 byte mDNS_snprintf.
693*4b22b933Srs200217
694*4b22b933Srs200217 Revision 1.338 2003/12/13 03:05:27 ksekar
695*4b22b933Srs200217 <rdar://problem/3192548>: DynDNS: Unicast query of service records
696*4b22b933Srs200217
697*4b22b933Srs200217 Revision 1.337 2003/12/01 21:46:05 cheshire
698*4b22b933Srs200217 mDNS_StartQuery returns mStatus_BadInterfaceErr if the specified interface does not exist
699*4b22b933Srs200217
700*4b22b933Srs200217 Revision 1.336 2003/12/01 21:26:19 cheshire
701*4b22b933Srs200217 Guard against zero-length sbuffer in mDNS_vsnprintf()
702*4b22b933Srs200217
703*4b22b933Srs200217 Revision 1.335 2003/12/01 20:27:48 cheshire
704*4b22b933Srs200217 Display IPv6 addresses correctly (e.g. in log messages) on little-endian processors
705*4b22b933Srs200217
706*4b22b933Srs200217 Revision 1.334 2003/11/20 22:59:53 cheshire
707*4b22b933Srs200217 Changed runtime checks in mDNS.c to be compile-time checks in mDNSEmbeddedAPI.h
708*4b22b933Srs200217 Thanks to Bob Bradley for suggesting the ingenious compiler trick to make this work.
709*4b22b933Srs200217
710*4b22b933Srs200217 Revision 1.333 2003/11/20 20:49:53 cheshire
711*4b22b933Srs200217 Another fix from HP: Use packedstruct macro to ensure proper packing for on-the-wire packet structures
712*4b22b933Srs200217
713*4b22b933Srs200217 Revision 1.332 2003/11/20 05:47:37 cheshire
714*4b22b933Srs200217 <rdar://problem/3490355>: Don't exclude known answers whose expiry time is before the next query
715*4b22b933Srs200217 Now that we only include answers in the known answer list if they are less than
716*4b22b933Srs200217 halfway to expiry, the check to also see if we have another query scheduled
717*4b22b933Srs200217 before the record expires is no longer necessary (and in fact, not correct).
718*4b22b933Srs200217
719*4b22b933Srs200217 Revision 1.331 2003/11/19 22:31:48 cheshire
720*4b22b933Srs200217 When automatically adding A records to SRVs, add them as additionals, not answers
721*4b22b933Srs200217
722*4b22b933Srs200217 Revision 1.330 2003/11/19 22:28:50 cheshire
723*4b22b933Srs200217 Increment/Decrement mDNS_reentrancy around calls to m->MainCallback()
724*4b22b933Srs200217 to allow client to make mDNS calls (specifically the call to mDNS_GrowCache())
725*4b22b933Srs200217
726*4b22b933Srs200217 Revision 1.329 2003/11/19 22:19:24 cheshire
727*4b22b933Srs200217 Show log message when ignoring packets with bad TTL.
728*4b22b933Srs200217 This is to help diagnose problems on Linux versions that may not report the TTL reliably.
729*4b22b933Srs200217
730*4b22b933Srs200217 Revision 1.328 2003/11/19 22:06:38 cheshire
731*4b22b933Srs200217 Show log messages when a service or hostname is renamed
732*4b22b933Srs200217
733*4b22b933Srs200217 Revision 1.327 2003/11/19 22:03:44 cheshire
734*4b22b933Srs200217 Move common "m->NextScheduledResponse = m->timenow" to before "if" statement
735*4b22b933Srs200217
736*4b22b933Srs200217 Revision 1.326 2003/11/17 22:27:02 cheshire
737*4b22b933Srs200217 Another fix from ramaprasad.kr@hp.com: Improve reply delay computation
738*4b22b933Srs200217 on platforms that have native clock rates below fifty ticks per second.
739*4b22b933Srs200217
740*4b22b933Srs200217 Revision 1.325 2003/11/17 20:41:44 cheshire
741*4b22b933Srs200217 Fix some missing mDNS_Lock(m)/mDNS_Unlock(m) calls.
742*4b22b933Srs200217
743*4b22b933Srs200217 Revision 1.324 2003/11/17 20:36:32 cheshire
744*4b22b933Srs200217 Function rename: Remove "mDNS_" prefix from AdvertiseInterface() and
745*4b22b933Srs200217 DeadvertiseInterface() -- they're internal private routines, not API routines.
746*4b22b933Srs200217
747*4b22b933Srs200217 Revision 1.323 2003/11/14 20:59:08 cheshire
748*4b22b933Srs200217 Clients can't use AssignDomainName macro because mDNSPlatformMemCopy is defined in mDNSPlatformFunctions.h.
749*4b22b933Srs200217 Best solution is just to combine mDNSEmbeddedAPI.h and mDNSPlatformFunctions.h into a single file.
750*4b22b933Srs200217
751*4b22b933Srs200217 Revision 1.322 2003/11/14 19:47:52 cheshire
752*4b22b933Srs200217 Define symbol MAX_ESCAPED_DOMAIN_NAME to indicate recommended buffer size for ConvertDomainNameToCString
753*4b22b933Srs200217
754*4b22b933Srs200217 Revision 1.321 2003/11/14 19:18:34 cheshire
755*4b22b933Srs200217 Move AssignDomainName macro to mDNSEmbeddedAPI.h to that client layers can use it too
756*4b22b933Srs200217
757*4b22b933Srs200217 Revision 1.320 2003/11/13 06:45:04 cheshire
758*4b22b933Srs200217 Fix compiler warning on certain compilers
759*4b22b933Srs200217
760*4b22b933Srs200217 Revision 1.319 2003/11/13 00:47:40 cheshire
761*4b22b933Srs200217 <rdar://problem/3437556> We should delay AAAA record query if A record already in cache.
762*4b22b933Srs200217
763*4b22b933Srs200217 Revision 1.318 2003/11/13 00:33:26 cheshire
764*4b22b933Srs200217 Change macro "RRIsAddressType" to "RRTypeIsAddressType"
765*4b22b933Srs200217
766*4b22b933Srs200217 Revision 1.317 2003/11/13 00:10:49 cheshire
767*4b22b933Srs200217 <rdar://problem/3436412>: Verify that rr data is different before updating.
768*4b22b933Srs200217
769*4b22b933Srs200217 Revision 1.316 2003/11/08 23:37:54 cheshire
770*4b22b933Srs200217 Give explicit zero initializers to blank static structure, required by certain compilers.
771*4b22b933Srs200217 (Thanks to ramaprasad.kr@hp.com for reporting this.)
772*4b22b933Srs200217
773*4b22b933Srs200217 Revision 1.315 2003/11/07 03:32:56 cheshire
774*4b22b933Srs200217 <rdar://problem/3472153> mDNSResponder delivers answers in inconsistent order
775*4b22b933Srs200217 This is the real fix. Checkin 1.312 was overly simplistic; Calling GetFreeCacheRR() can sometimes
776*4b22b933Srs200217 purge records from the cache, causing tail pointer *rp to be stale on return. The correct fix is
777*4b22b933Srs200217 to maintain a system-wide tail pointer for each cache slot, and then if neccesary GetFreeCacheRR()
778*4b22b933Srs200217 can update this pointer, so that mDNSCoreReceiveResponse() appends records in the right place.
779*4b22b933Srs200217
780*4b22b933Srs200217 Revision 1.314 2003/11/07 03:19:49 cheshire
781*4b22b933Srs200217 Minor variable renaming for clarity
782*4b22b933Srs200217
783*4b22b933Srs200217 Revision 1.313 2003/11/07 03:14:49 cheshire
784*4b22b933Srs200217 Previous checkin proved to be overly simplistic; reversing
785*4b22b933Srs200217
786*4b22b933Srs200217 Revision 1.312 2003/11/03 23:45:15 cheshire
787*4b22b933Srs200217 <rdar://problem/3472153> mDNSResponder delivers answers in inconsistent order
788*4b22b933Srs200217 Build cache lists in FIFO order, not customary C LIFO order
789*4b22b933Srs200217 (Append new elements to tail of cache list, instead of prepending at the head.)
790*4b22b933Srs200217
791*4b22b933Srs200217 Revision 1.311 2003/10/09 18:00:11 cheshire
792*4b22b933Srs200217 Another compiler warning fix.
793*4b22b933Srs200217
794*4b22b933Srs200217 Revision 1.310 2003/10/07 20:27:05 cheshire
795*4b22b933Srs200217 Patch from Bob Bradley, to fix warning and compile error on Windows
796*4b22b933Srs200217
797*4b22b933Srs200217 Revision 1.309 2003/09/26 01:06:36 cheshire
798*4b22b933Srs200217 <rdar://problem/3427923> Set kDNSClass_UniqueRRSet bit for updates too
799*4b22b933Srs200217 Made new routine HaveSentEntireRRSet() to check if flag should be set
800*4b22b933Srs200217
801*4b22b933Srs200217 Revision 1.308 2003/09/23 01:05:01 cheshire
802*4b22b933Srs200217 Minor changes to comments and debugf() message
803*4b22b933Srs200217
804*4b22b933Srs200217 Revision 1.307 2003/09/09 20:13:30 cheshire
805*4b22b933Srs200217 <rdar://problem/3411105> Don't send a Goodbye record if we never announced it
806*4b22b933Srs200217 Ammend checkin 1.304: Off-by-one error: By this place in the function we've already decremented
807*4b22b933Srs200217 rr->AnnounceCount, so the check needs to be for InitialAnnounceCount-1, not InitialAnnounceCount
808*4b22b933Srs200217
809*4b22b933Srs200217 Revision 1.306 2003/09/09 03:00:03 cheshire
810*4b22b933Srs200217 <rdar://problem/3413099> Services take a long time to disappear when switching networks.
811*4b22b933Srs200217 Added two constants: kDefaultReconfirmTimeForNoAnswer and kDefaultReconfirmTimeForCableDisconnect
812*4b22b933Srs200217
813*4b22b933Srs200217 Revision 1.305 2003/09/09 02:49:31 cheshire
814*4b22b933Srs200217 <rdar://problem/3413975> Initial probes and queries not grouped on wake-from-sleep
815*4b22b933Srs200217
816*4b22b933Srs200217 Revision 1.304 2003/09/09 02:41:19 cheshire
817*4b22b933Srs200217 <rdar://problem/3411105> Don't send a Goodbye record if we never announced it
818*4b22b933Srs200217
819*4b22b933Srs200217 Revision 1.303 2003/09/05 19:55:02 cheshire
820*4b22b933Srs200217 <rdar://problem/3409533> Include address records when announcing SRV records
821*4b22b933Srs200217
822*4b22b933Srs200217 Revision 1.302 2003/09/05 00:01:36 cheshire
823*4b22b933Srs200217 <rdar://problem/3407549> Don't accelerate queries that have large KA lists
824*4b22b933Srs200217
825*4b22b933Srs200217 Revision 1.301 2003/09/04 22:51:13 cheshire
826*4b22b933Srs200217 <rdar://problem/3398213> Group probes and goodbyes better
827*4b22b933Srs200217
828*4b22b933Srs200217 Revision 1.300 2003/09/03 02:40:37 cheshire
829*4b22b933Srs200217 <rdar://problem/3404842> mDNSResponder complains about '_'s
830*4b22b933Srs200217 Underscores are not supposed to be legal in standard DNS names, but IANA appears
831*4b22b933Srs200217 to have allowed them in previous service name registrations, so we should too.
832*4b22b933Srs200217
833*4b22b933Srs200217 Revision 1.299 2003/09/03 02:33:09 cheshire
834*4b22b933Srs200217 <rdar://problem/3404795> CacheRecordRmv ERROR
835*4b22b933Srs200217 Don't update m->NewQuestions until *after* CheckCacheExpiration();
836*4b22b933Srs200217
837*4b22b933Srs200217 Revision 1.298 2003/09/03 01:47:01 cheshire
838*4b22b933Srs200217 <rdar://problem/3319418> Services always in a state of flux
839*4b22b933Srs200217 Change mDNS_Reconfirm_internal() minimum timeout from 5 seconds to 45-60 seconds
840*4b22b933Srs200217
841*4b22b933Srs200217 Revision 1.297 2003/08/29 19:44:15 cheshire
842*4b22b933Srs200217 <rdar://problem/3400967> Traffic reduction: Eliminate synchronized QUs when a new service appears
843*4b22b933Srs200217 1. Use m->RandomQueryDelay to impose a random delay in the range 0-500ms on queries
844*4b22b933Srs200217 that already have at least one unique answer in the cache
845*4b22b933Srs200217 2. For these queries, go straight to QM, skipping QU
846*4b22b933Srs200217
847*4b22b933Srs200217 Revision 1.296 2003/08/29 19:08:21 cheshire
848*4b22b933Srs200217 <rdar://problem/3400986> Traffic reduction: Eliminate huge KA lists after wake from sleep
849*4b22b933Srs200217 Known answers are no longer eligible to go in the KA list if they are more than half-way to their expiry time.
850*4b22b933Srs200217
851*4b22b933Srs200217 Revision 1.295 2003/08/28 01:10:59 cheshire
852*4b22b933Srs200217 <rdar://problem/3396034> Add syslog message to report when query is reset because of immediate answer burst
853*4b22b933Srs200217
854*4b22b933Srs200217 Revision 1.294 2003/08/27 02:30:22 cheshire
855*4b22b933Srs200217 <rdar://problem/3395909> Traffic Reduction: Inefficiencies in DNSServiceResolverResolve()
856*4b22b933Srs200217 One more change: "query->GotTXT" is now a straightforward bi-state boolean again
857*4b22b933Srs200217
858*4b22b933Srs200217 Revision 1.293 2003/08/27 02:25:31 cheshire
859*4b22b933Srs200217 <rdar://problem/3395909> Traffic Reduction: Inefficiencies in DNSServiceResolverResolve()
860*4b22b933Srs200217
861*4b22b933Srs200217 Revision 1.292 2003/08/21 19:27:36 cheshire
862*4b22b933Srs200217 <rdar://problem/3387878> Traffic reduction: No need to announce record for longer than TTL
863*4b22b933Srs200217
864*4b22b933Srs200217 Revision 1.291 2003/08/21 18:57:44 cheshire
865*4b22b933Srs200217 <rdar://problem/3387140> Synchronized queries on the network
866*4b22b933Srs200217
867*4b22b933Srs200217 Revision 1.290 2003/08/21 02:25:23 cheshire
868*4b22b933Srs200217 Minor changes to comments and debugf() messages
869*4b22b933Srs200217
870*4b22b933Srs200217 Revision 1.289 2003/08/21 02:21:50 cheshire
871*4b22b933Srs200217 <rdar://problem/3386473> Efficiency: Reduce repeated queries
872*4b22b933Srs200217
873*4b22b933Srs200217 Revision 1.288 2003/08/20 23:39:30 cheshire
874*4b22b933Srs200217 <rdar://problem/3344098> Review syslog messages, and remove as appropriate
875*4b22b933Srs200217
876*4b22b933Srs200217 Revision 1.287 2003/08/20 20:47:18 cheshire
877*4b22b933Srs200217 Fix compiler warning
878*4b22b933Srs200217
879*4b22b933Srs200217 Revision 1.286 2003/08/20 02:18:51 cheshire
880*4b22b933Srs200217 <rdar://problem/3344098> Cleanup: Review syslog messages
881*4b22b933Srs200217
882*4b22b933Srs200217 Revision 1.285 2003/08/20 01:59:06 cheshire
883*4b22b933Srs200217 <rdar://problem/3384478> rdatahash and rdnamehash not updated after changing rdata
884*4b22b933Srs200217 Made new routine SetNewRData() to update rdlength, rdestimate, rdatahash and rdnamehash in one place
885*4b22b933Srs200217
886*4b22b933Srs200217 Revision 1.284 2003/08/19 22:20:00 cheshire
887*4b22b933Srs200217 <rdar://problem/3376721> Don't use IPv6 on interfaces that have a routable IPv4 address configured
888*4b22b933Srs200217 More minor refinements
889*4b22b933Srs200217
890*4b22b933Srs200217 Revision 1.283 2003/08/19 22:16:27 cheshire
891*4b22b933Srs200217 Minor fix: Add missing "mDNS_Unlock(m);" in mDNS_DeregisterInterface() error case.
892*4b22b933Srs200217
893*4b22b933Srs200217 Revision 1.282 2003/08/19 06:48:25 cheshire
894*4b22b933Srs200217 <rdar://problem/3376552> Guard against excessive record updates
895*4b22b933Srs200217 Each record starts with 10 UpdateCredits.
896*4b22b933Srs200217 Every update consumes one UpdateCredit.
897*4b22b933Srs200217 UpdateCredits are replenished at a rate of one one per minute, up to a maximum of 10.
898*4b22b933Srs200217 As the number of UpdateCredits declines, the number of announcements is similarly scaled back.
899*4b22b933Srs200217 When fewer than 5 UpdateCredits remain, the first announcement is also delayed by an increasing amount.
900*4b22b933Srs200217
901*4b22b933Srs200217 Revision 1.281 2003/08/19 04:49:28 cheshire
902*4b22b933Srs200217 <rdar://problem/3368159> Interaction between v4, v6 and dual-stack hosts not working quite right
903*4b22b933Srs200217 1. A dual-stack host should only suppress its own query if it sees the same query from other hosts on BOTH IPv4 and IPv6.
904*4b22b933Srs200217 2. When we see the first v4 (or first v6) member of a group, we re-trigger questions and probes on that interface.
905*4b22b933Srs200217 3. When we see the last v4 (or v6) member of a group go away, we revalidate all the records received on that interface.
906*4b22b933Srs200217
907*4b22b933Srs200217 Revision 1.280 2003/08/19 02:33:36 cheshire
908*4b22b933Srs200217 Update comments
909*4b22b933Srs200217
910*4b22b933Srs200217 Revision 1.279 2003/08/19 02:31:11 cheshire
911*4b22b933Srs200217 <rdar://problem/3378386> mDNSResponder overenthusiastic with final expiration queries
912*4b22b933Srs200217 Final expiration queries now only mark the question for sending on the particular interface
913*4b22b933Srs200217 pertaining to the record that's expiring.
914*4b22b933Srs200217
915*4b22b933Srs200217 Revision 1.278 2003/08/18 22:53:37 cheshire
916*4b22b933Srs200217 <rdar://problem/3382647> mDNSResponder divide by zero in mDNSPlatformRawTime()
917*4b22b933Srs200217
918*4b22b933Srs200217 Revision 1.277 2003/08/18 19:05:44 cheshire
919*4b22b933Srs200217 <rdar://problem/3382423> UpdateRecord not working right
920*4b22b933Srs200217 Added "newrdlength" field to hold new length of updated rdata
921*4b22b933Srs200217
922*4b22b933Srs200217 Revision 1.276 2003/08/16 03:39:00 cheshire
923*4b22b933Srs200217 <rdar://problem/3338440> InterfaceID -1 indicates "local only"
924*4b22b933Srs200217
925*4b22b933Srs200217 Revision 1.275 2003/08/16 02:51:27 cheshire
926*4b22b933Srs200217 <rdar://problem/3366590> mDNSResponder takes too much RPRVT
927*4b22b933Srs200217 Don't try to compute namehash etc, until *after* validating the name
928*4b22b933Srs200217
929*4b22b933Srs200217 Revision 1.274 2003/08/16 01:12:40 cheshire
930*4b22b933Srs200217 <rdar://problem/3366590> mDNSResponder takes too much RPRVT
931*4b22b933Srs200217 Now that the minimum rdata object size has been reduced to 64 bytes, it is no longer safe to do a
932*4b22b933Srs200217 simple C structure assignment of a domainname, because that object is defined to be 256 bytes long,
933*4b22b933Srs200217 and in the process of copying it, the C compiler may run off the end of the rdata object into
934*4b22b933Srs200217 unmapped memory. All assignments of domainname objects of uncertain size are now replaced with a
935*4b22b933Srs200217 call to the macro AssignDomainName(), which is careful to copy only as many bytes as are valid.
936*4b22b933Srs200217
937*4b22b933Srs200217 Revision 1.273 2003/08/15 20:16:02 cheshire
938*4b22b933Srs200217 <rdar://problem/3366590> mDNSResponder takes too much RPRVT
939*4b22b933Srs200217 We want to avoid touching the rdata pages, so we don't page them in.
940*4b22b933Srs200217 1. RDLength was stored with the rdata, which meant touching the page just to find the length.
941*4b22b933Srs200217 Moved this from the RData to the ResourceRecord object.
942*4b22b933Srs200217 2. To avoid unnecessarily touching the rdata just to compare it,
943*4b22b933Srs200217 compute a hash of the rdata and store the hash in the ResourceRecord object.
944*4b22b933Srs200217
945*4b22b933Srs200217 Revision 1.272 2003/08/14 19:29:04 cheshire
946*4b22b933Srs200217 <rdar://problem/3378473> Include cache records in SIGINFO output
947*4b22b933Srs200217 Moved declarations of DNSTypeName() and GetRRDisplayString to mDNSEmbeddedAPI.h so daemon.c can use them
948*4b22b933Srs200217
949*4b22b933Srs200217 Revision 1.271 2003/08/14 02:17:05 cheshire
950*4b22b933Srs200217 <rdar://problem/3375491> Split generic ResourceRecord type into two separate types: AuthRecord and CacheRecord
951*4b22b933Srs200217
952*4b22b933Srs200217 Revision 1.270 2003/08/13 17:07:28 ksekar
953*4b22b933Srs200217 <rdar://problem/3376458>: Extra RR linked to list even if registration fails - causes crash
954*4b22b933Srs200217 Added check to result of mDNS_Register() before linking extra record into list.
955*4b22b933Srs200217
956*4b22b933Srs200217 Revision 1.269 2003/08/12 19:56:23 cheshire
957*4b22b933Srs200217 Update to APSL 2.0
958*4b22b933Srs200217
959*4b22b933Srs200217 Revision 1.268 2003/08/12 15:01:10 cheshire
960*4b22b933Srs200217 Add comments
961*4b22b933Srs200217
962*4b22b933Srs200217 Revision 1.267 2003/08/12 14:59:27 cheshire
963*4b22b933Srs200217 <rdar://problem/3374490> Rate-limiting blocks some legitimate responses
964*4b22b933Srs200217 When setting LastMCTime also record LastMCInterface. When checking LastMCTime to determine
965*4b22b933Srs200217 whether to suppress the response, also check LastMCInterface to see if it matches.
966*4b22b933Srs200217
967*4b22b933Srs200217 Revision 1.266 2003/08/12 12:47:16 cheshire
968*4b22b933Srs200217 In mDNSCoreMachineSleep debugf message, display value of m->timenow
969*4b22b933Srs200217
970*4b22b933Srs200217 Revision 1.265 2003/08/11 20:04:28 cheshire
971*4b22b933Srs200217 <rdar://problem/3366553> Improve efficiency by restricting cases where we have to walk the entire cache
972*4b22b933Srs200217
973*4b22b933Srs200217 Revision 1.264 2003/08/09 00:55:02 cheshire
974*4b22b933Srs200217 <rdar://problem/3366553> mDNSResponder is taking 20-30% of the CPU
975*4b22b933Srs200217 Don't scan the whole cache after every packet.
976*4b22b933Srs200217
977*4b22b933Srs200217 Revision 1.263 2003/08/09 00:35:29 cheshire
978*4b22b933Srs200217 Moved AnswerNewQuestion() later in the file, in preparation for next checkin
979*4b22b933Srs200217
980*4b22b933Srs200217 Revision 1.262 2003/08/08 19:50:33 cheshire
981*4b22b933Srs200217 <rdar://problem/3370332> Remove "Cache size now xxx" messages
982*4b22b933Srs200217
983*4b22b933Srs200217 Revision 1.261 2003/08/08 19:18:45 cheshire
984*4b22b933Srs200217 <rdar://problem/3271219> Only retrigger questions on platforms with the "PhantomInterfaces" bug
985*4b22b933Srs200217
986*4b22b933Srs200217 Revision 1.260 2003/08/08 18:55:48 cheshire
987*4b22b933Srs200217 <rdar://problem/3370365> Guard against time going backwards
988*4b22b933Srs200217
989*4b22b933Srs200217 Revision 1.259 2003/08/08 18:36:04 cheshire
990*4b22b933Srs200217 <rdar://problem/3344154> Only need to revalidate on interface removal on platforms that have the PhantomInterfaces bug
991*4b22b933Srs200217
992*4b22b933Srs200217 Revision 1.258 2003/08/08 16:22:05 cheshire
993*4b22b933Srs200217 <rdar://problem/3335473> Need to check validity of TXT (and other) records
994*4b22b933Srs200217 Remove unneeded LogMsg
995*4b22b933Srs200217
996*4b22b933Srs200217 Revision 1.257 2003/08/07 01:41:08 cheshire
997*4b22b933Srs200217 <rdar://problem/3367346> Ignore packets with invalid source address (all zeroes or all ones)
998*4b22b933Srs200217
999*4b22b933Srs200217 Revision 1.256 2003/08/06 23:25:51 cheshire
1000*4b22b933Srs200217 <rdar://problem/3290674> Increase TTL for A/AAAA/SRV from one minute to four
1001*4b22b933Srs200217
1002*4b22b933Srs200217 Revision 1.255 2003/08/06 23:22:50 cheshire
1003*4b22b933Srs200217 Add symbolic constants: kDefaultTTLforUnique (one minute) and kDefaultTTLforShared (two hours)
1004*4b22b933Srs200217
1005*4b22b933Srs200217 Revision 1.254 2003/08/06 21:33:39 cheshire
1006*4b22b933Srs200217 Fix compiler warnings on PocketPC 2003 (Windows CE)
1007*4b22b933Srs200217
1008*4b22b933Srs200217 Revision 1.253 2003/08/06 20:43:57 cheshire
1009*4b22b933Srs200217 <rdar://problem/3335473> Need to check validity of TXT (and other) records
1010*4b22b933Srs200217 Created ValidateDomainName() and ValidateRData(), used by mDNS_Register_internal() and mDNS_Update()
1011*4b22b933Srs200217
1012*4b22b933Srs200217 Revision 1.252 2003/08/06 20:35:47 cheshire
1013*4b22b933Srs200217 Enhance debugging routine GetRRDisplayString() so it can also be used to display
1014*4b22b933Srs200217 other RDataBody objects, not just the one currently attached the given ResourceRecord
1015*4b22b933Srs200217
1016*4b22b933Srs200217 Revision 1.251 2003/08/06 19:07:34 cheshire
1017*4b22b933Srs200217 <rdar://problem/3366251> mDNSResponder not inhibiting multicast responses as much as it should
1018*4b22b933Srs200217 Was checking LastAPTime instead of LastMCTime
1019*4b22b933Srs200217
1020*4b22b933Srs200217 Revision 1.250 2003/08/06 19:01:55 cheshire
1021*4b22b933Srs200217 Update comments
1022*4b22b933Srs200217
1023*4b22b933Srs200217 Revision 1.249 2003/08/06 00:13:28 cheshire
1024*4b22b933Srs200217 Tidy up debugf messages
1025*4b22b933Srs200217
1026*4b22b933Srs200217 Revision 1.248 2003/08/05 22:20:15 cheshire
1027*4b22b933Srs200217 <rdar://problem/3330324> Need to check IP TTL on responses
1028*4b22b933Srs200217
1029*4b22b933Srs200217 Revision 1.247 2003/08/05 00:56:39 cheshire
1030*4b22b933Srs200217 <rdar://problem/3357075> mDNSResponder sending additional records, even after precursor record suppressed
1031*4b22b933Srs200217
1032*4b22b933Srs200217 Revision 1.246 2003/08/04 19:20:49 cheshire
1033*4b22b933Srs200217 Add kDNSQType_ANY to list in DNSTypeName() so it can be displayed in debugging messages
1034*4b22b933Srs200217
1035*4b22b933Srs200217 Revision 1.245 2003/08/02 01:56:29 cheshire
1036*4b22b933Srs200217 For debugging: log message if we ever get more than one question in a truncated packet
1037*4b22b933Srs200217
1038*4b22b933Srs200217 Revision 1.244 2003/08/01 23:55:32 cheshire
1039*4b22b933Srs200217 Fix for compiler warnings on Windows, submitted by Bob Bradley
1040*4b22b933Srs200217
1041*4b22b933Srs200217 Revision 1.243 2003/07/25 02:26:09 cheshire
1042*4b22b933Srs200217 Typo: FIxed missing semicolon
1043*4b22b933Srs200217
1044*4b22b933Srs200217 Revision 1.242 2003/07/25 01:18:41 cheshire
1045*4b22b933Srs200217 Fix memory leak on shutdown in mDNS_Close() (detected in Windows version)
1046*4b22b933Srs200217
1047*4b22b933Srs200217 Revision 1.241 2003/07/23 21:03:42 cheshire
1048*4b22b933Srs200217 Only show "Found record..." debugf message in verbose mode
1049*4b22b933Srs200217
1050*4b22b933Srs200217 Revision 1.240 2003/07/23 21:01:11 cheshire
1051*4b22b933Srs200217 <rdar://problem/3340584> Need Nagle-style algorithm to coalesce multiple packets into one
1052*4b22b933Srs200217 After sending a packet, suppress further sending for the next 100ms.
1053*4b22b933Srs200217
1054*4b22b933Srs200217 Revision 1.239 2003/07/22 01:30:05 cheshire
1055*4b22b933Srs200217 <rdar://problem/3329099> Don't try to add the same question to the duplicate-questions list more than once
1056*4b22b933Srs200217
1057*4b22b933Srs200217 Revision 1.238 2003/07/22 00:10:20 cheshire
1058*4b22b933Srs200217 <rdar://problem/3337355> ConvertDomainLabelToCString() needs to escape escape characters
1059*4b22b933Srs200217
1060*4b22b933Srs200217 Revision 1.237 2003/07/19 03:23:13 cheshire
1061*4b22b933Srs200217 <rdar://problem/2986147> mDNSResponder needs to receive and cache larger records
1062*4b22b933Srs200217
1063*4b22b933Srs200217 Revision 1.236 2003/07/19 03:04:55 cheshire
1064*4b22b933Srs200217 Fix warnings; some debugf message improvements
1065*4b22b933Srs200217
1066*4b22b933Srs200217 Revision 1.235 2003/07/19 00:03:32 cheshire
1067*4b22b933Srs200217 <rdar://problem/3160248> ScheduleNextTask needs to be smarter after a no-op packet is received
1068*4b22b933Srs200217 ScheduleNextTask is quite an expensive operation.
1069*4b22b933Srs200217 We don't need to do all that work after receiving a no-op packet that didn't change our state.
1070*4b22b933Srs200217
1071*4b22b933Srs200217 Revision 1.234 2003/07/18 23:52:11 cheshire
1072*4b22b933Srs200217 To improve consistency of field naming, global search-and-replace:
1073*4b22b933Srs200217 NextProbeTime -> NextScheduledProbe
1074*4b22b933Srs200217 NextResponseTime -> NextScheduledResponse
1075*4b22b933Srs200217
1076*4b22b933Srs200217 Revision 1.233 2003/07/18 00:29:59 cheshire
1077*4b22b933Srs200217 <rdar://problem/3268878> Remove mDNSResponder version from packet header and use HINFO record instead
1078*4b22b933Srs200217
1079*4b22b933Srs200217 Revision 1.232 2003/07/18 00:11:38 cheshire
1080*4b22b933Srs200217 Add extra case to switch statements to handle HINFO data for Get, Put and Display
1081*4b22b933Srs200217 (In all but GetRDLength(), this is is just a fall-through to kDNSType_TXT)
1082*4b22b933Srs200217
1083*4b22b933Srs200217 Revision 1.231 2003/07/18 00:06:37 cheshire
1084*4b22b933Srs200217 To make code a little easier to read in GetRDLength(), search-and-replace "rr->rdata->u." with "rd->"
1085*4b22b933Srs200217
1086*4b22b933Srs200217 Revision 1.230 2003/07/17 18:16:54 cheshire
1087*4b22b933Srs200217 <rdar://problem/3319418> Services always in a state of flux
1088*4b22b933Srs200217 In preparation for working on this, made some debugf messages a little more selective
1089*4b22b933Srs200217
1090*4b22b933Srs200217 Revision 1.229 2003/07/17 17:35:04 cheshire
1091*4b22b933Srs200217 <rdar://problem/3325583> Rate-limit responses, to guard against packet flooding
1092*4b22b933Srs200217
1093*4b22b933Srs200217 Revision 1.228 2003/07/16 20:50:27 cheshire
1094*4b22b933Srs200217 <rdar://problem/3315761> Need to implement "unicast response" request, using top bit of qclass
1095*4b22b933Srs200217
1096*4b22b933Srs200217 Revision 1.227 2003/07/16 05:01:36 cheshire
1097*4b22b933Srs200217 Add fields 'LargeAnswers' and 'ExpectUnicastResponse' in preparation for
1098*4b22b933Srs200217 <rdar://problem/3315761> Need to implement "unicast response" request, using top bit of qclass
1099*4b22b933Srs200217
1100*4b22b933Srs200217 Revision 1.226 2003/07/16 04:51:44 cheshire
1101*4b22b933Srs200217 Fix use of constant 'mDNSPlatformOneSecond' where it should have said 'InitialQuestionInterval'
1102*4b22b933Srs200217
1103*4b22b933Srs200217 Revision 1.225 2003/07/16 04:46:41 cheshire
1104*4b22b933Srs200217 Minor wording cleanup: The correct DNS term is "response", not "reply"
1105*4b22b933Srs200217
1106*4b22b933Srs200217 Revision 1.224 2003/07/16 04:39:02 cheshire
1107*4b22b933Srs200217 Textual cleanup (no change to functionality):
1108*4b22b933Srs200217 Construct "c >= 'A' && c <= 'Z'" appears in too many places; replaced with macro "mDNSIsUpperCase(c)"
1109*4b22b933Srs200217
1110*4b22b933Srs200217 Revision 1.223 2003/07/16 00:09:22 cheshire
1111*4b22b933Srs200217 Textual cleanup (no change to functionality):
1112*4b22b933Srs200217 Construct "((mDNSs32)rr->rroriginalttl * mDNSPlatformOneSecond)" appears in too many places;
1113*4b22b933Srs200217 replace with macro "TicksTTL(rr)"
1114*4b22b933Srs200217 Construct "rr->TimeRcvd + ((mDNSs32)rr->rroriginalttl * mDNSPlatformOneSecond)"
1115*4b22b933Srs200217 replaced with macro "RRExpireTime(rr)"
1116*4b22b933Srs200217
1117*4b22b933Srs200217 Revision 1.222 2003/07/15 23:40:46 cheshire
1118*4b22b933Srs200217 Function rename: UpdateDupSuppressInfo() is more accurately called ExpireDupSuppressInfo()
1119*4b22b933Srs200217
1120*4b22b933Srs200217 Revision 1.221 2003/07/15 22:17:56 cheshire
1121*4b22b933Srs200217 <rdar://problem/3328394> mDNSResponder is not being efficient when doing certain queries
1122*4b22b933Srs200217
1123*4b22b933Srs200217 Revision 1.220 2003/07/15 02:12:51 cheshire
1124*4b22b933Srs200217 Slight tidy-up of debugf messages and comments
1125*4b22b933Srs200217
1126*4b22b933Srs200217 Revision 1.219 2003/07/15 01:55:12 cheshire
1127*4b22b933Srs200217 <rdar://problem/3315777> Need to implement service registration with subtypes
1128*4b22b933Srs200217
1129*4b22b933Srs200217 Revision 1.218 2003/07/14 16:26:06 cheshire
1130*4b22b933Srs200217 <rdar://problem/3324795> Duplicate query suppression not working right
1131*4b22b933Srs200217 Refinement: Don't record DS information for a question in the first quarter second
1132*4b22b933Srs200217 right after we send it -- in the case where a question happens to be accelerated by
1133*4b22b933Srs200217 the maximum allowed amount, we don't want it to then be suppressed because the previous
1134*4b22b933Srs200217 time *we* sent that question falls (just) within the valid duplicate suppression window.
1135*4b22b933Srs200217
1136*4b22b933Srs200217 Revision 1.217 2003/07/13 04:43:53 cheshire
1137*4b22b933Srs200217 <rdar://problem/3325169> Services on multiple interfaces not always resolving
1138*4b22b933Srs200217 Minor refinement: No need to make address query broader than the original SRV query that provoked it
1139*4b22b933Srs200217
1140*4b22b933Srs200217 Revision 1.216 2003/07/13 03:13:17 cheshire
1141*4b22b933Srs200217 <rdar://problem/3325169> Services on multiple interfaces not always resolving
1142*4b22b933Srs200217 If we get an identical SRV on a second interface, convert address queries to non-specific
1143*4b22b933Srs200217
1144*4b22b933Srs200217 Revision 1.215 2003/07/13 02:28:00 cheshire
1145*4b22b933Srs200217 <rdar://problem/3325166> SendResponses didn't all its responses
1146*4b22b933Srs200217 Delete all references to RRInterfaceActive -- it's now superfluous
1147*4b22b933Srs200217
1148*4b22b933Srs200217 Revision 1.214 2003/07/13 01:47:53 cheshire
1149*4b22b933Srs200217 Fix one error and one warning in the Windows build
1150*4b22b933Srs200217
1151*4b22b933Srs200217 Revision 1.213 2003/07/12 04:25:48 cheshire
1152*4b22b933Srs200217 Fix minor signed/unsigned warnings
1153*4b22b933Srs200217
1154*4b22b933Srs200217 Revision 1.212 2003/07/12 01:59:11 cheshire
1155*4b22b933Srs200217 Minor changes to debugf messages
1156*4b22b933Srs200217
1157*4b22b933Srs200217 Revision 1.211 2003/07/12 01:47:01 cheshire
1158*4b22b933Srs200217 <rdar://problem/3324495> After name conflict, appended number should be higher than previous number
1159*4b22b933Srs200217
1160*4b22b933Srs200217 Revision 1.210 2003/07/12 01:43:28 cheshire
1161*4b22b933Srs200217 <rdar://problem/3324795> Duplicate query suppression not working right
1162*4b22b933Srs200217 The correct cutoff time for duplicate query suppression is timenow less one-half the query interval.
1163*4b22b933Srs200217 The code was incorrectly using the last query time plus one-half the query interval.
1164*4b22b933Srs200217 This was only correct in the case where query acceleration was not in effect.
1165*4b22b933Srs200217
1166*4b22b933Srs200217 Revision 1.209 2003/07/12 01:27:50 cheshire
1167*4b22b933Srs200217 <rdar://problem/3320079> Hostname conflict naming should not use two hyphens
1168*4b22b933Srs200217 Fix missing "-1" in RemoveLabelSuffix()
1169*4b22b933Srs200217
1170*4b22b933Srs200217 Revision 1.208 2003/07/11 01:32:38 cheshire
1171*4b22b933Srs200217 Syntactic cleanup (no change to funcationality): Now that we only have one host name,
1172*4b22b933Srs200217 rename field "hostname1" to "hostname", and field "RR_A1" to "RR_A".
1173*4b22b933Srs200217
1174*4b22b933Srs200217 Revision 1.207 2003/07/11 01:28:00 cheshire
1175*4b22b933Srs200217 <rdar://problem/3161289> No more local.arpa
1176*4b22b933Srs200217
1177*4b22b933Srs200217 Revision 1.206 2003/07/11 00:45:02 cheshire
1178*4b22b933Srs200217 <rdar://problem/3321909> Client should get callback confirming successful host name registration
1179*4b22b933Srs200217
1180*4b22b933Srs200217 Revision 1.205 2003/07/11 00:40:18 cheshire
1181*4b22b933Srs200217 Tidy up debug message in HostNameCallback()
1182*4b22b933Srs200217
1183*4b22b933Srs200217 Revision 1.204 2003/07/11 00:20:32 cheshire
1184*4b22b933Srs200217 <rdar://problem/3320087> mDNSResponder should log a message after 16 unsuccessful probes
1185*4b22b933Srs200217
1186*4b22b933Srs200217 Revision 1.203 2003/07/10 23:53:41 cheshire
1187*4b22b933Srs200217 <rdar://problem/3320079> Hostname conflict naming should not use two hyphens
1188*4b22b933Srs200217
1189*4b22b933Srs200217 Revision 1.202 2003/07/04 02:23:20 cheshire
1190*4b22b933Srs200217 <rdar://problem/3311955> Responder too aggressive at flushing stale data
1191*4b22b933Srs200217 Changed mDNSResponder to require four unanswered queries before purging a record, instead of two.
1192*4b22b933Srs200217
1193*4b22b933Srs200217 Revision 1.201 2003/07/04 01:09:41 cheshire
1194*4b22b933Srs200217 <rdar://problem/3315775> Need to implement subtype queries
1195*4b22b933Srs200217 Modified ConstructServiceName() to allow three-part service types
1196*4b22b933Srs200217
1197*4b22b933Srs200217 Revision 1.200 2003/07/03 23:55:26 cheshire
1198*4b22b933Srs200217 Minor change to wording of syslog warning messages
1199*4b22b933Srs200217
1200*4b22b933Srs200217 Revision 1.199 2003/07/03 23:51:13 cheshire
1201*4b22b933Srs200217 <rdar://problem/3315652>: Lots of "have given xxx answers" syslog warnings
1202*4b22b933Srs200217 Added more detailed debugging information
1203*4b22b933Srs200217
1204*4b22b933Srs200217 Revision 1.198 2003/07/03 22:19:30 cheshire
1205*4b22b933Srs200217 <rdar://problem/3314346> Bug fix in 3274153 breaks TiVo
1206*4b22b933Srs200217 Make exception to allow _tivo_servemedia._tcp.
1207*4b22b933Srs200217
1208*4b22b933Srs200217 Revision 1.197 2003/07/02 22:33:05 cheshire
1209*4b22b933Srs200217 <rdar://problem/2986146> mDNSResponder needs to start with a smaller cache and then grow it as needed
1210*4b22b933Srs200217 Minor refinements:
1211*4b22b933Srs200217 When cache is exhausted, verify that rrcache_totalused == rrcache_size and report if not
1212*4b22b933Srs200217 Allow cache to grow to 512 records before considering it a potential denial-of-service attack
1213*4b22b933Srs200217
1214*4b22b933Srs200217 Revision 1.196 2003/07/02 21:19:45 cheshire
1215*4b22b933Srs200217 <rdar://problem/3313413> Update copyright notices, etc., in source code comments
1216*4b22b933Srs200217
1217*4b22b933Srs200217 Revision 1.195 2003/07/02 19:56:58 cheshire
1218*4b22b933Srs200217 <rdar://problem/2986146> mDNSResponder needs to start with a smaller cache and then grow it as needed
1219*4b22b933Srs200217 Minor refinement: m->rrcache_active was not being decremented when
1220*4b22b933Srs200217 an active record was deleted because its TTL expired
1221*4b22b933Srs200217
1222*4b22b933Srs200217 Revision 1.194 2003/07/02 18:47:40 cheshire
1223*4b22b933Srs200217 Minor wording change to log messages
1224*4b22b933Srs200217
1225*4b22b933Srs200217 Revision 1.193 2003/07/02 02:44:13 cheshire
1226*4b22b933Srs200217 Fix warning in non-debug build
1227*4b22b933Srs200217
1228*4b22b933Srs200217 Revision 1.192 2003/07/02 02:41:23 cheshire
1229*4b22b933Srs200217 <rdar://problem/2986146> mDNSResponder needs to start with a smaller cache and then grow it as needed
1230*4b22b933Srs200217
1231*4b22b933Srs200217 Revision 1.191 2003/07/02 02:30:51 cheshire
1232*4b22b933Srs200217 HashSlot() returns an array index. It can't be negative; hence it should not be signed.
1233*4b22b933Srs200217
1234*4b22b933Srs200217 Revision 1.190 2003/06/27 00:03:05 vlubet
1235*4b22b933Srs200217 <rdar://problem/3304625> Merge of build failure fix for gcc 3.3
1236*4b22b933Srs200217
1237*4b22b933Srs200217 Revision 1.189 2003/06/11 19:24:03 cheshire
1238*4b22b933Srs200217 <rdar://problem/3287141> Crash in SendQueries/SendResponses when no active interfaces
1239*4b22b933Srs200217 Slight refinement to previous checkin
1240*4b22b933Srs200217
1241*4b22b933Srs200217 Revision 1.188 2003/06/10 20:33:28 cheshire
1242*4b22b933Srs200217 <rdar://problem/3287141> Crash in SendQueries/SendResponses when no active interfaces
1243*4b22b933Srs200217
1244*4b22b933Srs200217 Revision 1.187 2003/06/10 04:30:44 cheshire
1245*4b22b933Srs200217 <rdar://problem/3286234> Need to re-probe/re-announce on configuration change
1246*4b22b933Srs200217 Only interface-specific records were re-probing and re-announcing, not non-specific records.
1247*4b22b933Srs200217
1248*4b22b933Srs200217 Revision 1.186 2003/06/10 04:24:39 cheshire
1249*4b22b933Srs200217 <rdar://problem/3283637> React when we observe other people query unsuccessfully for a record that's in our cache
1250*4b22b933Srs200217 Some additional refinements:
1251*4b22b933Srs200217 Don't try to do this for unicast-response queries
1252*4b22b933Srs200217 better tracking of Qs and KAs in multi-packet KA lists
1253*4b22b933Srs200217
1254*4b22b933Srs200217 Revision 1.185 2003/06/10 03:52:49 cheshire
1255*4b22b933Srs200217 Update comments and debug messages
1256*4b22b933Srs200217
1257*4b22b933Srs200217 Revision 1.184 2003/06/10 02:26:39 cheshire
1258*4b22b933Srs200217 <rdar://problem/3283516> mDNSResponder needs an mDNS_Reconfirm() function
1259*4b22b933Srs200217 Make mDNS_Reconfirm() call mDNS_Lock(), like the other API routines
1260*4b22b933Srs200217
1261*4b22b933Srs200217 Revision 1.183 2003/06/09 18:53:13 cheshire
1262*4b22b933Srs200217 Simplify some debugf() statements (replaced block of 25 lines with 2 lines)
1263*4b22b933Srs200217
1264*4b22b933Srs200217 Revision 1.182 2003/06/09 18:38:42 cheshire
1265*4b22b933Srs200217 <rdar://problem/3285082> Need to be more tolerant when there are mDNS proxies on the network
1266*4b22b933Srs200217 Only issue a correction if the TTL in the proxy packet is less than half the correct value.
1267*4b22b933Srs200217
1268*4b22b933Srs200217 Revision 1.181 2003/06/07 06:45:05 cheshire
1269*4b22b933Srs200217 <rdar://problem/3283666> No need for multiple machines to all be sending the same queries
1270*4b22b933Srs200217
1271*4b22b933Srs200217 Revision 1.180 2003/06/07 06:31:07 cheshire
1272*4b22b933Srs200217 Create little four-line helper function "FindIdenticalRecordInCache()"
1273*4b22b933Srs200217
1274*4b22b933Srs200217 Revision 1.179 2003/06/07 06:28:13 cheshire
1275*4b22b933Srs200217 For clarity, change name of "DNSQuestion q" to "DNSQuestion pktq"
1276*4b22b933Srs200217
1277*4b22b933Srs200217 Revision 1.178 2003/06/07 06:25:12 cheshire
1278*4b22b933Srs200217 Update some comments
1279*4b22b933Srs200217
1280*4b22b933Srs200217 Revision 1.177 2003/06/07 04:50:53 cheshire
1281*4b22b933Srs200217 <rdar://problem/3283637> React when we observe other people query unsuccessfully for a record that's in our cache
1282*4b22b933Srs200217
1283*4b22b933Srs200217 Revision 1.176 2003/06/07 04:33:26 cheshire
1284*4b22b933Srs200217 <rdar://problem/3283540> When query produces zero results, call mDNS_Reconfirm() on any antecedent records
1285*4b22b933Srs200217 Minor change: Increment/decrement logic for q->CurrentAnswers should be in
1286*4b22b933Srs200217 CacheRecordAdd() and CacheRecordRmv(), not AnswerQuestionWithResourceRecord()
1287*4b22b933Srs200217
1288*4b22b933Srs200217 Revision 1.175 2003/06/07 04:11:52 cheshire
1289*4b22b933Srs200217 Minor changes to comments and debug messages
1290*4b22b933Srs200217
1291*4b22b933Srs200217 Revision 1.174 2003/06/07 01:46:38 cheshire
1292*4b22b933Srs200217 <rdar://problem/3283540> When query produces zero results, call mDNS_Reconfirm() on any antecedent records
1293*4b22b933Srs200217
1294*4b22b933Srs200217 Revision 1.173 2003/06/07 01:22:13 cheshire
1295*4b22b933Srs200217 <rdar://problem/3283516> mDNSResponder needs an mDNS_Reconfirm() function
1296*4b22b933Srs200217
1297*4b22b933Srs200217 Revision 1.172 2003/06/07 00:59:42 cheshire
1298*4b22b933Srs200217 <rdar://problem/3283454> Need some randomness to spread queries on the network
1299*4b22b933Srs200217
1300*4b22b933Srs200217 Revision 1.171 2003/06/06 21:41:10 cheshire
1301*4b22b933Srs200217 For consistency, mDNS_StopQuery() should return an mStatus result, just like all the other mDNSCore routines
1302*4b22b933Srs200217
1303*4b22b933Srs200217 Revision 1.170 2003/06/06 21:38:55 cheshire
1304*4b22b933Srs200217 Renamed 'NewData' as 'FreshData' (The data may not be new data, just a refresh of data that we
1305*4b22b933Srs200217 already had in our cache. This refreshes our TTL on the data, but the data itself stays the same.)
1306*4b22b933Srs200217
1307*4b22b933Srs200217 Revision 1.169 2003/06/06 21:35:55 cheshire
1308*4b22b933Srs200217 Fix mis-named macro: GetRRHostNameTarget is really GetRRDomainNameTarget
1309*4b22b933Srs200217 (the target is a domain name, but not necessarily a host name)
1310*4b22b933Srs200217
1311*4b22b933Srs200217 Revision 1.168 2003/06/06 21:33:31 cheshire
1312*4b22b933Srs200217 Instead of using (mDNSPlatformOneSecond/2) all over the place, define a constant "InitialQuestionInterval"
1313*4b22b933Srs200217
1314*4b22b933Srs200217 Revision 1.167 2003/06/06 21:30:42 cheshire
1315*4b22b933Srs200217 <rdar://problem/3282962> Don't delay queries for shared record types
1316*4b22b933Srs200217
1317*4b22b933Srs200217 Revision 1.166 2003/06/06 17:20:14 cheshire
1318*4b22b933Srs200217 For clarity, rename question fields name/rrtype/rrclass as qname/qtype/qclass
1319*4b22b933Srs200217 (Global search-and-replace; no functional change to code execution.)
1320*4b22b933Srs200217
1321*4b22b933Srs200217 Revision 1.165 2003/06/04 02:53:21 cheshire
1322*4b22b933Srs200217 Add some "#pragma warning" lines so it compiles clean on Microsoft compilers
1323*4b22b933Srs200217
1324*4b22b933Srs200217 Revision 1.164 2003/06/04 01:25:33 cheshire
1325*4b22b933Srs200217 <rdar://problem/3274950> Cannot perform multi-packet known-answer suppression messages
1326*4b22b933Srs200217 Display time interval between first and subsequent queries
1327*4b22b933Srs200217
1328*4b22b933Srs200217 Revision 1.163 2003/06/03 19:58:14 cheshire
1329*4b22b933Srs200217 <rdar://problem/3277665> mDNS_DeregisterService() fixes:
1330*4b22b933Srs200217 When forcibly deregistering after a conflict, ensure we don't send an incorrect goodbye packet.
1331*4b22b933Srs200217 Guard against a couple of possible mDNS_DeregisterService() race conditions.
1332*4b22b933Srs200217
1333*4b22b933Srs200217 Revision 1.162 2003/06/03 19:30:39 cheshire
1334*4b22b933Srs200217 Minor addition refinements for
1335*4b22b933Srs200217 <rdar://problem/3277080> Duplicate registrations not handled as efficiently as they should be
1336*4b22b933Srs200217
1337*4b22b933Srs200217 Revision 1.161 2003/06/03 18:29:03 cheshire
1338*4b22b933Srs200217 Minor changes to comments and debugf() messages
1339*4b22b933Srs200217
1340*4b22b933Srs200217 Revision 1.160 2003/06/03 05:02:16 cheshire
1341*4b22b933Srs200217 <rdar://problem/3277080> Duplicate registrations not handled as efficiently as they should be
1342*4b22b933Srs200217
1343*4b22b933Srs200217 Revision 1.159 2003/06/03 03:31:57 cheshire
1344*4b22b933Srs200217 <rdar://problem/3277033> False self-conflict when there are duplicate registrations on one machine
1345*4b22b933Srs200217
1346*4b22b933Srs200217 Revision 1.158 2003/06/02 22:57:09 cheshire
1347*4b22b933Srs200217 Minor clarifying changes to comments and log messages;
1348*4b22b933Srs200217 IdenticalResourceRecordAnyInterface() is really more accurately called just IdenticalResourceRecord()
1349*4b22b933Srs200217
1350*4b22b933Srs200217 Revision 1.157 2003/05/31 00:09:49 cheshire
1351*4b22b933Srs200217 <rdar://problem/3274862> Add ability to discover what services are on a network
1352*4b22b933Srs200217
1353*4b22b933Srs200217 Revision 1.156 2003/05/30 23:56:49 cheshire
1354*4b22b933Srs200217 <rdar://problem/3274847> Crash after error in mDNS_RegisterService()
1355*4b22b933Srs200217 Need to set "sr->Extras = mDNSNULL" before returning
1356*4b22b933Srs200217
1357*4b22b933Srs200217 Revision 1.155 2003/05/30 23:48:00 cheshire
1358*4b22b933Srs200217 <rdar://problem/3274832> Announcements not properly grouped
1359*4b22b933Srs200217 Due to inconsistent setting of rr->LastAPTime at different places in the
1360*4b22b933Srs200217 code, announcements were not properly grouped into a single packet.
1361*4b22b933Srs200217 Fixed by creating a single routine called InitializeLastAPTime().
1362*4b22b933Srs200217
1363*4b22b933Srs200217 Revision 1.154 2003/05/30 23:38:14 cheshire
1364*4b22b933Srs200217 <rdar://problem/3274814> Fix error in IPv6 reverse-mapping PTR records
1365*4b22b933Srs200217 Wrote buffer[32] where it should have said buffer[64]
1366*4b22b933Srs200217
1367*4b22b933Srs200217 Revision 1.153 2003/05/30 19:10:56 cheshire
1368*4b22b933Srs200217 <rdar://problem/3274153> ConstructServiceName needs to be more restrictive
1369*4b22b933Srs200217
1370*4b22b933Srs200217 Revision 1.152 2003/05/29 22:39:16 cheshire
1371*4b22b933Srs200217 <rdar://problem/3273209> Don't truncate strings in the middle of a UTF-8 character
1372*4b22b933Srs200217
1373*4b22b933Srs200217 Revision 1.151 2003/05/29 06:35:42 cheshire
1374*4b22b933Srs200217 <rdar://problem/3272221> mDNSCoreReceiveResponse() purging wrong record
1375*4b22b933Srs200217
1376*4b22b933Srs200217 Revision 1.150 2003/05/29 06:25:45 cheshire
1377*4b22b933Srs200217 <rdar://problem/3272218> Need to call CheckCacheExpiration() *before* AnswerNewQuestion()
1378*4b22b933Srs200217
1379*4b22b933Srs200217 Revision 1.149 2003/05/29 06:18:39 cheshire
1380*4b22b933Srs200217 <rdar://problem/3272217> Split AnswerLocalQuestions into CacheRecordAdd and CacheRecordRmv
1381*4b22b933Srs200217
1382*4b22b933Srs200217 Revision 1.148 2003/05/29 06:11:34 cheshire
1383*4b22b933Srs200217 <rdar://problem/3272214> Report if there appear to be too many "Resolve" callbacks
1384*4b22b933Srs200217
1385*4b22b933Srs200217 Revision 1.147 2003/05/29 06:01:18 cheshire
1386*4b22b933Srs200217 Change some debugf() calls to LogMsg() calls to help with debugging
1387*4b22b933Srs200217
1388*4b22b933Srs200217 Revision 1.146 2003/05/28 21:00:44 cheshire
1389*4b22b933Srs200217 Re-enable "immediate answer burst" debugf message
1390*4b22b933Srs200217
1391*4b22b933Srs200217 Revision 1.145 2003/05/28 20:57:44 cheshire
1392*4b22b933Srs200217 <rdar://problem/3271550> mDNSResponder reports "Cannot perform multi-packet
1393*4b22b933Srs200217 known-answer suppression ..." This is a known issue caused by a bug in the OS X 10.2
1394*4b22b933Srs200217 version of mDNSResponder, so for now we should suppress this warning message.
1395*4b22b933Srs200217
1396*4b22b933Srs200217 Revision 1.144 2003/05/28 18:05:12 cheshire
1397*4b22b933Srs200217 <rdar://problem/3009899> mDNSResponder allows invalid service registrations
1398*4b22b933Srs200217 Fix silly mistake: old logic allowed "TDP" and "UCP" as valid names
1399*4b22b933Srs200217
1400*4b22b933Srs200217 Revision 1.143 2003/05/28 04:31:29 cheshire
1401*4b22b933Srs200217 <rdar://problem/3270733> mDNSResponder not sending probes at the prescribed time
1402*4b22b933Srs200217
1403*4b22b933Srs200217 Revision 1.142 2003/05/28 03:13:07 cheshire
1404*4b22b933Srs200217 <rdar://problem/3009899> mDNSResponder allows invalid service registrations
1405*4b22b933Srs200217 Require that the transport protocol be _udp or _tcp
1406*4b22b933Srs200217
1407*4b22b933Srs200217 Revision 1.141 2003/05/28 02:19:12 cheshire
1408*4b22b933Srs200217 <rdar://problem/3270634> Misleading messages generated by iChat
1409*4b22b933Srs200217 Better fix: Only generate the log message for queries where the TC bit is set.
1410*4b22b933Srs200217
1411*4b22b933Srs200217 Revision 1.140 2003/05/28 01:55:24 cheshire
1412*4b22b933Srs200217 Minor change to log messages
1413*4b22b933Srs200217
1414*4b22b933Srs200217 Revision 1.139 2003/05/28 01:52:51 cheshire
1415*4b22b933Srs200217 <rdar://problem/3270634> Misleading messages generated by iChat
1416*4b22b933Srs200217
1417*4b22b933Srs200217 Revision 1.138 2003/05/27 22:35:00 cheshire
1418*4b22b933Srs200217 <rdar://problem/3270277> mDNS_RegisterInterface needs to retrigger questions
1419*4b22b933Srs200217
1420*4b22b933Srs200217 Revision 1.137 2003/05/27 20:04:33 cheshire
1421*4b22b933Srs200217 <rdar://problem/3269900> mDNSResponder crash in mDNS_vsnprintf()
1422*4b22b933Srs200217
1423*4b22b933Srs200217 Revision 1.136 2003/05/27 18:50:07 cheshire
1424*4b22b933Srs200217 <rdar://problem/3269768> mDNS_StartResolveService doesn't inform client of port number changes
1425*4b22b933Srs200217
1426*4b22b933Srs200217 Revision 1.135 2003/05/26 04:57:28 cheshire
1427*4b22b933Srs200217 <rdar://problem/3268953> Delay queries when there are already answers in the cache
1428*4b22b933Srs200217
1429*4b22b933Srs200217 Revision 1.134 2003/05/26 04:54:54 cheshire
1430*4b22b933Srs200217 <rdar://problem/3268904> sprintf/vsprintf-style functions are unsafe; use snprintf/vsnprintf instead
1431*4b22b933Srs200217 Accidentally deleted '%' case from the switch statement
1432*4b22b933Srs200217
1433*4b22b933Srs200217 Revision 1.133 2003/05/26 03:21:27 cheshire
1434*4b22b933Srs200217 Tidy up address structure naming:
1435*4b22b933Srs200217 mDNSIPAddr => mDNSv4Addr (for consistency with mDNSv6Addr)
1436*4b22b933Srs200217 mDNSAddr.addr.ipv4 => mDNSAddr.ip.v4
1437*4b22b933Srs200217 mDNSAddr.addr.ipv6 => mDNSAddr.ip.v6
1438*4b22b933Srs200217
1439*4b22b933Srs200217 Revision 1.132 2003/05/26 03:01:26 cheshire
1440*4b22b933Srs200217 <rdar://problem/3268904> sprintf/vsprintf-style functions are unsafe; use snprintf/vsnprintf instead
1441*4b22b933Srs200217
1442*4b22b933Srs200217 Revision 1.131 2003/05/26 00:42:05 cheshire
1443*4b22b933Srs200217 <rdar://problem/3268876> Temporarily include mDNSResponder version in packets
1444*4b22b933Srs200217
1445*4b22b933Srs200217 Revision 1.130 2003/05/24 16:39:48 cheshire
1446*4b22b933Srs200217 <rdar://problem/3268631> SendResponses also needs to handle multihoming better
1447*4b22b933Srs200217
1448*4b22b933Srs200217 Revision 1.129 2003/05/23 02:15:37 cheshire
1449*4b22b933Srs200217 Fixed misleading use of the term "duplicate suppression" where it should have
1450*4b22b933Srs200217 said "known answer suppression". (Duplicate answer suppression is something
1451*4b22b933Srs200217 different, and duplicate question suppression is yet another thing, so the use
1452*4b22b933Srs200217 of the completely vague term "duplicate suppression" was particularly bad.)
1453*4b22b933Srs200217
1454*4b22b933Srs200217 Revision 1.128 2003/05/23 01:55:13 cheshire
1455*4b22b933Srs200217 <rdar://problem/3267127> After name change, mDNSResponder needs to re-probe for name uniqueness
1456*4b22b933Srs200217
1457*4b22b933Srs200217 Revision 1.127 2003/05/23 01:02:15 ksekar
1458*4b22b933Srs200217 <rdar://problem/3032577>: mDNSResponder needs to include unique id in default name
1459*4b22b933Srs200217
1460*4b22b933Srs200217 Revision 1.126 2003/05/22 02:29:22 cheshire
1461*4b22b933Srs200217 <rdar://problem/2984918> SendQueries needs to handle multihoming better
1462*4b22b933Srs200217 Complete rewrite of SendQueries. Works much better now :-)
1463*4b22b933Srs200217
1464*4b22b933Srs200217 Revision 1.125 2003/05/22 01:50:45 cheshire
1465*4b22b933Srs200217 Fix warnings, and improve log messages
1466*4b22b933Srs200217
1467*4b22b933Srs200217 Revision 1.124 2003/05/22 01:41:50 cheshire
1468*4b22b933Srs200217 DiscardDeregistrations doesn't need InterfaceID parameter
1469*4b22b933Srs200217
1470*4b22b933Srs200217 Revision 1.123 2003/05/22 01:38:55 cheshire
1471*4b22b933Srs200217 Change bracketing of #pragma mark
1472*4b22b933Srs200217
1473*4b22b933Srs200217 Revision 1.122 2003/05/21 19:59:04 cheshire
1474*4b22b933Srs200217 <rdar://problem/3148431> ER: Tweak responder's default name conflict behavior
1475*4b22b933Srs200217 Minor refinements; make sure we don't truncate in the middle of a multi-byte UTF-8 character
1476*4b22b933Srs200217
1477*4b22b933Srs200217 Revision 1.121 2003/05/21 17:54:07 ksekar
1478*4b22b933Srs200217 <rdar://problem/3148431> ER: Tweak responder's default name conflict behavior
1479*4b22b933Srs200217 New rename behavior - domain name "foo" becomes "foo--2" on conflict, richtext name becomes "foo (2)"
1480*4b22b933Srs200217
1481*4b22b933Srs200217 Revision 1.120 2003/05/19 22:14:14 ksekar
1482*4b22b933Srs200217 <rdar://problem/3162914> mDNS probe denials/conflicts not detected unless conflict is of the same type
1483*4b22b933Srs200217
1484*4b22b933Srs200217 Revision 1.119 2003/05/16 01:34:10 cheshire
1485*4b22b933Srs200217 Fix some warnings
1486*4b22b933Srs200217
1487*4b22b933Srs200217 Revision 1.118 2003/05/14 18:48:40 cheshire
1488*4b22b933Srs200217 <rdar://problem/3159272> mDNSResponder should be smarter about reconfigurations
1489*4b22b933Srs200217 More minor refinements:
1490*4b22b933Srs200217 mDNSMacOSX.c needs to do *all* its mDNS_DeregisterInterface calls before freeing memory
1491*4b22b933Srs200217 mDNS_DeregisterInterface revalidates cache record when *any* representative of an interface goes away
1492*4b22b933Srs200217
1493*4b22b933Srs200217 Revision 1.117 2003/05/14 07:08:36 cheshire
1494*4b22b933Srs200217 <rdar://problem/3159272> mDNSResponder should be smarter about reconfigurations
1495*4b22b933Srs200217 Previously, when there was any network configuration change, mDNSResponder
1496*4b22b933Srs200217 would tear down the entire list of active interfaces and start again.
1497*4b22b933Srs200217 That was very disruptive, and caused the entire cache to be flushed,
1498*4b22b933Srs200217 and caused lots of extra network traffic. Now it only removes interfaces
1499*4b22b933Srs200217 that have really gone, and only adds new ones that weren't there before.
1500*4b22b933Srs200217
1501*4b22b933Srs200217 Revision 1.116 2003/05/14 06:51:56 cheshire
1502*4b22b933Srs200217 <rdar://problem/3027144> mDNSResponder doesn't refresh server info if changed during sleep
1503*4b22b933Srs200217
1504*4b22b933Srs200217 Revision 1.115 2003/05/14 06:44:31 cheshire
1505*4b22b933Srs200217 Improve debugging message
1506*4b22b933Srs200217
1507*4b22b933Srs200217 Revision 1.114 2003/05/07 01:47:03 cheshire
1508*4b22b933Srs200217 <rdar://problem/3250330> Also protect against NULL domainlabels
1509*4b22b933Srs200217
1510*4b22b933Srs200217 Revision 1.113 2003/05/07 00:28:18 cheshire
1511*4b22b933Srs200217 <rdar://problem/3250330> Need to make mDNSResponder more defensive against bad clients
1512*4b22b933Srs200217
1513*4b22b933Srs200217 Revision 1.112 2003/05/06 00:00:46 cheshire
1514*4b22b933Srs200217 <rdar://problem/3248914> Rationalize naming of domainname manipulation functions
1515*4b22b933Srs200217
1516*4b22b933Srs200217 Revision 1.111 2003/05/05 23:42:08 cheshire
1517*4b22b933Srs200217 <rdar://problem/3245631> Resolves never succeed
1518*4b22b933Srs200217 Was setting "rr->LastAPTime = timenow - rr->LastAPTime"
1519*4b22b933Srs200217 instead of "rr->LastAPTime = timenow - rr->ThisAPInterval"
1520*4b22b933Srs200217
1521*4b22b933Srs200217 Revision 1.110 2003/04/30 21:09:59 cheshire
1522*4b22b933Srs200217 <rdar://problem/3244727> mDNS_vsnprintf needs to be more defensive against invalid domain names
1523*4b22b933Srs200217
1524*4b22b933Srs200217 Revision 1.109 2003/04/26 02:41:56 cheshire
1525*4b22b933Srs200217 <rdar://problem/3241281> Change timenow from a local variable to a structure member
1526*4b22b933Srs200217
1527*4b22b933Srs200217 Revision 1.108 2003/04/25 01:45:56 cheshire
1528*4b22b933Srs200217 <rdar://problem/3240002> mDNS_RegisterNoSuchService needs to include a host name
1529*4b22b933Srs200217
1530*4b22b933Srs200217 Revision 1.107 2003/04/25 00:41:31 cheshire
1531*4b22b933Srs200217 <rdar://problem/3239912> Create single routine PurgeCacheResourceRecord(), to avoid bugs in future
1532*4b22b933Srs200217
1533*4b22b933Srs200217 Revision 1.106 2003/04/22 03:14:45 cheshire
1534*4b22b933Srs200217 <rdar://problem/3232229> Include Include instrumented mDNSResponder in panther now
1535*4b22b933Srs200217
1536*4b22b933Srs200217 Revision 1.105 2003/04/22 01:07:43 cheshire
1537*4b22b933Srs200217 <rdar://problem/3176248> DNSServiceRegistrationUpdateRecord should support a default ttl
1538*4b22b933Srs200217 If TTL parameter is zero, leave record TTL unchanged
1539*4b22b933Srs200217
1540*4b22b933Srs200217 Revision 1.104 2003/04/21 19:15:52 cheshire
1541*4b22b933Srs200217 Fix some compiler warnings
1542*4b22b933Srs200217
1543*4b22b933Srs200217 Revision 1.103 2003/04/19 02:26:35 cheshire
1544*4b22b933Srs200217 <rdar://problem/3233804> Incorrect goodbye packet after conflict
1545*4b22b933Srs200217
1546*4b22b933Srs200217 Revision 1.102 2003/04/17 03:06:28 cheshire
1547*4b22b933Srs200217 <rdar://problem/3231321> No need to query again when a service goes away
1548*4b22b933Srs200217 Set UnansweredQueries to 2 when receiving a "goodbye" packet
1549*4b22b933Srs200217
1550*4b22b933Srs200217 Revision 1.101 2003/04/15 20:58:31 jgraessl
1551*4b22b933Srs200217 <rdar://problem/3229014> Added a hash to lookup records in the cache.
1552*4b22b933Srs200217
1553*4b22b933Srs200217 Revision 1.100 2003/04/15 18:53:14 cheshire
1554*4b22b933Srs200217 <rdar://problem/3229064> Bug in ScheduleNextTask
1555*4b22b933Srs200217 mDNS.c 1.94 incorrectly combined two "if" statements into one.
1556*4b22b933Srs200217
1557*4b22b933Srs200217 Revision 1.99 2003/04/15 18:09:13 jgraessl
1558*4b22b933Srs200217 <rdar://problem/3228892>
1559*4b22b933Srs200217 Reviewed by: Stuart Cheshire
1560*4b22b933Srs200217 Added code to keep track of when the next cache item will expire so we can
1561*4b22b933Srs200217 call TidyRRCache only when necessary.
1562*4b22b933Srs200217
1563*4b22b933Srs200217 Revision 1.98 2003/04/03 03:43:55 cheshire
1564*4b22b933Srs200217 <rdar://problem/3216837> Off-by-one error in probe rate limiting
1565*4b22b933Srs200217
1566*4b22b933Srs200217 Revision 1.97 2003/04/02 01:48:17 cheshire
1567*4b22b933Srs200217 <rdar://problem/3212360> mDNSResponder sometimes suffers false self-conflicts when it sees its own packets
1568*4b22b933Srs200217 Additional fix pointed out by Josh:
1569*4b22b933Srs200217 Also set ProbeFailTime when incrementing NumFailedProbes when resetting a record back to probing state
1570*4b22b933Srs200217
1571*4b22b933Srs200217 Revision 1.96 2003/04/01 23:58:55 cheshire
1572*4b22b933Srs200217 Minor comment changes
1573*4b22b933Srs200217
1574*4b22b933Srs200217 Revision 1.95 2003/04/01 23:46:05 cheshire
1575*4b22b933Srs200217 <rdar://problem/3214832> mDNSResponder can get stuck in infinite loop after many location cycles
1576*4b22b933Srs200217 mDNS_DeregisterInterface() flushes the RR cache by marking all records received on that interface
1577*4b22b933Srs200217 to expire in one second. However, if a mDNS_StartResolveService() call is made in that one-second
1578*4b22b933Srs200217 window, it can get an SRV answer from one of those soon-to-be-deleted records, resulting in
1579*4b22b933Srs200217 FoundServiceInfoSRV() making an interface-specific query on the interface that was just removed.
1580*4b22b933Srs200217
1581*4b22b933Srs200217 Revision 1.94 2003/03/29 01:55:19 cheshire
1582*4b22b933Srs200217 <rdar://problem/3212360> mDNSResponder sometimes suffers false self-conflicts when it sees its own packets
1583*4b22b933Srs200217 Solution: Major cleanup of packet timing and conflict handling rules
1584*4b22b933Srs200217
1585*4b22b933Srs200217 Revision 1.93 2003/03/28 01:54:36 cheshire
1586*4b22b933Srs200217 Minor tidyup of IPv6 (AAAA) code
1587*4b22b933Srs200217
1588*4b22b933Srs200217 Revision 1.92 2003/03/27 03:30:55 cheshire
1589*4b22b933Srs200217 <rdar://problem/3210018> Name conflicts not handled properly, resulting in memory corruption, and eventual crash
1590*4b22b933Srs200217 Problem was that HostNameCallback() was calling mDNS_DeregisterInterface(), which is not safe in a callback
1591*4b22b933Srs200217 Fixes:
1592*4b22b933Srs200217 1. Make mDNS_DeregisterInterface() safe to call from a callback
1593*4b22b933Srs200217 2. Make HostNameCallback() use DeadvertiseInterface() instead
1594*4b22b933Srs200217 (it never really needed to deregister the interface at all)
1595*4b22b933Srs200217
1596*4b22b933Srs200217 Revision 1.91 2003/03/15 04:40:36 cheshire
1597*4b22b933Srs200217 Change type called "mDNSOpaqueID" to the more descriptive name "mDNSInterfaceID"
1598*4b22b933Srs200217
1599*4b22b933Srs200217 Revision 1.90 2003/03/14 20:26:37 cheshire
1600*4b22b933Srs200217 Reduce debugging messages (reclassify some "debugf" as "verbosedebugf")
1601*4b22b933Srs200217
1602*4b22b933Srs200217 Revision 1.89 2003/03/12 19:57:50 cheshire
1603*4b22b933Srs200217 Fixed typo in debug message
1604*4b22b933Srs200217
1605*4b22b933Srs200217 Revision 1.88 2003/03/12 00:17:44 cheshire
1606*4b22b933Srs200217 <rdar://problem/3195426> GetFreeCacheRR needs to be more willing to throw away recent records
1607*4b22b933Srs200217
1608*4b22b933Srs200217 Revision 1.87 2003/03/11 01:27:20 cheshire
1609*4b22b933Srs200217 Reduce debugging messages (reclassify some "debugf" as "verbosedebugf")
1610*4b22b933Srs200217
1611*4b22b933Srs200217 Revision 1.86 2003/03/06 20:44:33 cheshire
1612*4b22b933Srs200217 Comment tidyup
1613*4b22b933Srs200217
1614*4b22b933Srs200217 Revision 1.85 2003/03/05 03:38:35 cheshire
1615*4b22b933Srs200217 <rdar://problem/3185731> Bogus error message in console: died or deallocated, but no record of client can be found!
1616*4b22b933Srs200217 Fixed by leaving client in list after conflict, until client explicitly deallocates
1617*4b22b933Srs200217
1618*4b22b933Srs200217 Revision 1.84 2003/03/05 01:27:30 cheshire
1619*4b22b933Srs200217 <rdar://problem/3185482> Different TTL for multicast versus unicast responses
1620*4b22b933Srs200217 When building unicast responses, record TTLs are capped to 10 seconds
1621*4b22b933Srs200217
1622*4b22b933Srs200217 Revision 1.83 2003/03/04 23:48:52 cheshire
1623*4b22b933Srs200217 <rdar://problem/3188865> Double probes after wake from sleep
1624*4b22b933Srs200217 Don't reset record type to kDNSRecordTypeUnique if record is DependentOn another
1625*4b22b933Srs200217
1626*4b22b933Srs200217 Revision 1.82 2003/03/04 23:38:29 cheshire
1627*4b22b933Srs200217 <rdar://problem/3099194> mDNSResponder needs performance improvements
1628*4b22b933Srs200217 Only set rr->CRActiveQuestion to point to the
1629*4b22b933Srs200217 currently active representative of a question set
1630*4b22b933Srs200217
1631*4b22b933Srs200217 Revision 1.81 2003/02/21 03:35:34 cheshire
1632*4b22b933Srs200217 <rdar://problem/3179007> mDNSResponder needs to include AAAA records in additional answer section
1633*4b22b933Srs200217
1634*4b22b933Srs200217 Revision 1.80 2003/02/21 02:47:53 cheshire
1635*4b22b933Srs200217 <rdar://problem/3099194> mDNSResponder needs performance improvements
1636*4b22b933Srs200217 Several places in the code were calling CacheRRActive(), which searched the entire
1637*4b22b933Srs200217 question list every time, to see if this cache resource record answers any question.
1638*4b22b933Srs200217 Instead, we now have a field "CRActiveQuestion" in the resource record structure
1639*4b22b933Srs200217
1640*4b22b933Srs200217 Revision 1.79 2003/02/21 01:54:07 cheshire
1641*4b22b933Srs200217 <rdar://problem/3099194> mDNSResponder needs performance improvements
1642*4b22b933Srs200217 Switched to using new "mDNS_Execute" model (see "Implementer Notes.txt")
1643*4b22b933Srs200217
1644*4b22b933Srs200217 Revision 1.78 2003/02/20 06:48:32 cheshire
1645*4b22b933Srs200217 <rdar://problem/3169535> Xserve RAID needs to do interface-specific registrations
1646*4b22b933Srs200217 Reviewed by: Josh Graessley, Bob Bradley
1647*4b22b933Srs200217
1648*4b22b933Srs200217 Revision 1.77 2003/01/31 03:35:59 cheshire
1649*4b22b933Srs200217 <rdar://problem/3147097> mDNSResponder sometimes fails to find the correct results
1650*4b22b933Srs200217 When there were *two* active questions in the list, they were incorrectly
1651*4b22b933Srs200217 finding *each other* and *both* being marked as duplicates of another question
1652*4b22b933Srs200217
1653*4b22b933Srs200217 Revision 1.76 2003/01/29 02:46:37 cheshire
1654*4b22b933Srs200217 Fix for IPv6:
1655*4b22b933Srs200217 A physical interface is identified solely by its InterfaceID (not by IP and type).
1656*4b22b933Srs200217 On a given InterfaceID, mDNSCore may send both v4 and v6 multicasts.
1657*4b22b933Srs200217 In cases where the requested outbound protocol (v4 or v6) is not supported on
1658*4b22b933Srs200217 that InterfaceID, the platform support layer should simply discard that packet.
1659*4b22b933Srs200217
1660*4b22b933Srs200217 Revision 1.75 2003/01/29 01:47:40 cheshire
1661*4b22b933Srs200217 Rename 'Active' to 'CRActive' or 'InterfaceActive' for improved clarity
1662*4b22b933Srs200217
1663*4b22b933Srs200217 Revision 1.74 2003/01/28 05:26:25 cheshire
1664*4b22b933Srs200217 <rdar://problem/3147097> mDNSResponder sometimes fails to find the correct results
1665*4b22b933Srs200217 Add 'Active' flag for interfaces
1666*4b22b933Srs200217
1667*4b22b933Srs200217 Revision 1.73 2003/01/28 03:45:12 cheshire
1668*4b22b933Srs200217 Fixed missing "not" in "!mDNSAddrIsDNSMulticast(dstaddr)"
1669*4b22b933Srs200217
1670*4b22b933Srs200217 Revision 1.72 2003/01/28 01:49:48 cheshire
1671*4b22b933Srs200217 <rdar://problem/3147097> mDNSResponder sometimes fails to find the correct results
1672*4b22b933Srs200217 FindDuplicateQuestion() was incorrectly finding the question itself in the list,
1673*4b22b933Srs200217 and incorrectly marking it as a duplicate (of itself), so that it became inactive.
1674*4b22b933Srs200217
1675*4b22b933Srs200217 Revision 1.71 2003/01/28 01:41:44 cheshire
1676*4b22b933Srs200217 <rdar://problem/3153091> Race condition when network change causes bad stuff
1677*4b22b933Srs200217 When an interface goes away, interface-specific questions on that interface become orphaned.
1678*4b22b933Srs200217 Orphan questions cause HaveQueries to return true, but there's no interface to send them on.
1679*4b22b933Srs200217 Fix: mDNS_DeregisterInterface() now calls DeActivateInterfaceQuestions()
1680*4b22b933Srs200217
1681*4b22b933Srs200217 Revision 1.70 2003/01/23 19:00:20 cheshire
1682*4b22b933Srs200217 Protect against infinite loops in mDNS_Execute
1683*4b22b933Srs200217
1684*4b22b933Srs200217 Revision 1.69 2003/01/21 22:56:32 jgraessl
1685*4b22b933Srs200217 <rdar://problem/3124348> service name changes are not properly handled
1686*4b22b933Srs200217 Submitted by: Stuart Cheshire
1687*4b22b933Srs200217 Reviewed by: Joshua Graessley
1688*4b22b933Srs200217 Applying changes for 3124348 to main branch. 3124348 changes went in to a
1689*4b22b933Srs200217 branch for SU.
1690*4b22b933Srs200217
1691*4b22b933Srs200217 Revision 1.68 2003/01/17 04:09:27 cheshire
1692*4b22b933Srs200217 <rdar://problem/3141038> mDNSResponder Resolves are unreliable on multi-homed hosts
1693*4b22b933Srs200217
1694*4b22b933Srs200217 Revision 1.67 2003/01/17 03:56:45 cheshire
1695*4b22b933Srs200217 Default 24-hour TTL is far too long. Changing to two hours.
1696*4b22b933Srs200217
1697*4b22b933Srs200217 Revision 1.66 2003/01/13 23:49:41 jgraessl
1698*4b22b933Srs200217 Merged changes for the following fixes in to top of tree:
1699*4b22b933Srs200217 <rdar://problem/3086540> computer name changes not handled properly
1700*4b22b933Srs200217 <rdar://problem/3124348> service name changes are not properly handled
1701*4b22b933Srs200217 <rdar://problem/3124352> announcements sent in pairs, failing chattiness test
1702*4b22b933Srs200217
1703*4b22b933Srs200217 Revision 1.65 2002/12/23 22:13:28 jgraessl
1704*4b22b933Srs200217 Reviewed by: Stuart Cheshire
1705*4b22b933Srs200217 Initial IPv6 support for mDNSResponder.
1706*4b22b933Srs200217
1707*4b22b933Srs200217 Revision 1.64 2002/11/26 20:49:06 cheshire
1708*4b22b933Srs200217 <rdar://problem/3104543> RFC 1123 allows the first character of a name label to be either a letter or a digit
1709*4b22b933Srs200217
1710*4b22b933Srs200217 Revision 1.63 2002/09/21 20:44:49 zarzycki
1711*4b22b933Srs200217 Added APSL info
1712*4b22b933Srs200217
1713*4b22b933Srs200217 Revision 1.62 2002/09/20 03:25:37 cheshire
1714*4b22b933Srs200217 Fix some compiler warnings
1715*4b22b933Srs200217
1716*4b22b933Srs200217 Revision 1.61 2002/09/20 01:05:24 cheshire
1717*4b22b933Srs200217 Don't kill the Extras list in mDNS_DeregisterService()
1718*4b22b933Srs200217
1719*4b22b933Srs200217 Revision 1.60 2002/09/19 23:47:35 cheshire
1720*4b22b933Srs200217 Added mDNS_RegisterNoSuchService() function for assertion of non-existence
1721*4b22b933Srs200217 of a particular named service
1722*4b22b933Srs200217
1723*4b22b933Srs200217 Revision 1.59 2002/09/19 21:25:34 cheshire
1724*4b22b933Srs200217 mDNS_snprintf() doesn't need to be in a separate file
1725*4b22b933Srs200217
1726*4b22b933Srs200217 Revision 1.58 2002/09/19 04:20:43 cheshire
1727*4b22b933Srs200217 Remove high-ascii characters that confuse some systems
1728*4b22b933Srs200217
1729*4b22b933Srs200217 Revision 1.57 2002/09/17 01:07:08 cheshire
1730*4b22b933Srs200217 Change mDNS_AdvertiseLocalAddresses to be a parameter to mDNS_Init()
1731*4b22b933Srs200217
1732*4b22b933Srs200217 Revision 1.56 2002/09/16 19:44:17 cheshire
1733*4b22b933Srs200217 Merge in license terms from Quinn's copy, in preparation for Darwin release
1734*4b22b933Srs200217 */
1735*4b22b933Srs200217
1736*4b22b933Srs200217 #pragma ident "%Z%%M% %I% %E% SMI"
1737*4b22b933Srs200217
1738*4b22b933Srs200217 #include "DNSCommon.h" // Defines general DNS untility routines
1739*4b22b933Srs200217 #include "uDNS.h" // Defines entry points into unicast-specific routines
1740*4b22b933Srs200217 // Disable certain benign warnings with Microsoft compilers
1741*4b22b933Srs200217 #if(defined(_MSC_VER))
1742*4b22b933Srs200217 // Disable "conditional expression is constant" warning for debug macros.
1743*4b22b933Srs200217 // Otherwise, this generates warnings for the perfectly natural construct "while(1)"
1744*4b22b933Srs200217 // If someone knows a variant way of writing "while(1)" that doesn't generate warning messages, please let us know
1745*4b22b933Srs200217 #pragma warning(disable:4127)
1746*4b22b933Srs200217
1747*4b22b933Srs200217 // Disable "assignment within conditional expression".
1748*4b22b933Srs200217 // Other compilers understand the convention that if you place the assignment expression within an extra pair
1749*4b22b933Srs200217 // of parentheses, this signals to the compiler that you really intended an assignment and no warning is necessary.
1750*4b22b933Srs200217 // The Microsoft compiler doesn't understand this convention, so in the absense of any other way to signal
1751*4b22b933Srs200217 // to the compiler that the assignment is intentional, we have to just turn this warning off completely.
1752*4b22b933Srs200217 #pragma warning(disable:4706)
1753*4b22b933Srs200217 #endif
1754*4b22b933Srs200217
1755*4b22b933Srs200217 // ***************************************************************************
1756*4b22b933Srs200217 #if COMPILER_LIKES_PRAGMA_MARK
1757*4b22b933Srs200217 #pragma mark -
1758*4b22b933Srs200217 #pragma mark - Program Constants
1759*4b22b933Srs200217 #endif
1760*4b22b933Srs200217
1761*4b22b933Srs200217 mDNSexport const mDNSIPPort zeroIPPort = { { 0 } };
1762*4b22b933Srs200217 mDNSexport const mDNSv4Addr zerov4Addr = { { 0 } };
1763*4b22b933Srs200217 mDNSexport const mDNSv6Addr zerov6Addr = { { 0 } };
1764*4b22b933Srs200217 mDNSexport const mDNSEthAddr zeroEthAddr = { { 0 } };
1765*4b22b933Srs200217 mDNSexport const mDNSv4Addr onesIPv4Addr = { { 255, 255, 255, 255 } };
1766*4b22b933Srs200217 mDNSexport const mDNSv6Addr onesIPv6Addr = { { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 } };
1767*4b22b933Srs200217 mDNSexport const mDNSAddr zeroAddr = { mDNSAddrType_None, {{{ 0 }}} };
1768*4b22b933Srs200217
1769*4b22b933Srs200217 mDNSexport const mDNSInterfaceID mDNSInterface_Any = 0;
1770*4b22b933Srs200217 mDNSexport const mDNSInterfaceID mDNSInterface_LocalOnly = (mDNSInterfaceID)1;
1771*4b22b933Srs200217
1772*4b22b933Srs200217 mDNSlocal const mDNSInterfaceID mDNSInterfaceMark = (mDNSInterfaceID)~0;
1773*4b22b933Srs200217
1774*4b22b933Srs200217 #define UnicastDNSPortAsNumber 53
1775*4b22b933Srs200217 #define NATPMPPortAsNumber 5351
1776*4b22b933Srs200217 #define DNSEXTPortAsNumber 5352 // Port used for end-to-end DNS operations like LLQ, Updates with Leases, etc.
1777*4b22b933Srs200217 #define MulticastDNSPortAsNumber 5353
1778*4b22b933Srs200217 #define LoopbackIPCPortAsNumber 5354
1779*4b22b933Srs200217
1780*4b22b933Srs200217 mDNSexport const mDNSIPPort UnicastDNSPort = { { UnicastDNSPortAsNumber >> 8, UnicastDNSPortAsNumber & 0xFF } };
1781*4b22b933Srs200217 mDNSexport const mDNSIPPort NATPMPPort = { { NATPMPPortAsNumber >> 8, NATPMPPortAsNumber & 0xFF } };
1782*4b22b933Srs200217 mDNSexport const mDNSIPPort DNSEXTPort = { { DNSEXTPortAsNumber >> 8, DNSEXTPortAsNumber & 0xFF } };
1783*4b22b933Srs200217 mDNSexport const mDNSIPPort MulticastDNSPort = { { MulticastDNSPortAsNumber >> 8, MulticastDNSPortAsNumber & 0xFF } };
1784*4b22b933Srs200217 mDNSexport const mDNSIPPort LoopbackIPCPort = { { LoopbackIPCPortAsNumber >> 8, LoopbackIPCPortAsNumber & 0xFF } };
1785*4b22b933Srs200217
1786*4b22b933Srs200217 mDNSexport const mDNSv4Addr AllDNSAdminGroup = { { 239, 255, 255, 251 } };
1787*4b22b933Srs200217 mDNSexport const mDNSAddr AllDNSLinkGroup_v4 = { mDNSAddrType_IPv4, { { { 224, 0, 0, 251 } } } };
1788*4b22b933Srs200217 mDNSexport const mDNSAddr AllDNSLinkGroup_v6 = { mDNSAddrType_IPv6, { { { 0xFF,0x02,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0xFB } } } };
1789*4b22b933Srs200217
1790*4b22b933Srs200217 mDNSexport const mDNSOpaque16 zeroID = { { 0, 0 } };
1791*4b22b933Srs200217 mDNSexport const mDNSOpaque16 QueryFlags = { { kDNSFlag0_QR_Query | kDNSFlag0_OP_StdQuery, 0 } };
1792*4b22b933Srs200217 mDNSexport const mDNSOpaque16 uQueryFlags = { { kDNSFlag0_QR_Query | kDNSFlag0_OP_StdQuery | kDNSFlag0_RD, 0 } };
1793*4b22b933Srs200217 mDNSexport const mDNSOpaque16 ResponseFlags = { { kDNSFlag0_QR_Response | kDNSFlag0_OP_StdQuery | kDNSFlag0_AA, 0 } };
1794*4b22b933Srs200217 mDNSexport const mDNSOpaque16 UpdateReqFlags = { { kDNSFlag0_QR_Query | kDNSFlag0_OP_Update, 0 } };
1795*4b22b933Srs200217 mDNSexport const mDNSOpaque16 UpdateRespFlags = { { kDNSFlag0_QR_Response | kDNSFlag0_OP_Update, 0 } };
1796*4b22b933Srs200217
1797*4b22b933Srs200217 // Any records bigger than this are considered 'large' records
1798*4b22b933Srs200217 #define SmallRecordLimit 1024
1799*4b22b933Srs200217
1800*4b22b933Srs200217 #define kMaxUpdateCredits 10
1801*4b22b933Srs200217 #define kUpdateCreditRefreshInterval (mDNSPlatformOneSecond * 6)
1802*4b22b933Srs200217
1803*4b22b933Srs200217 mDNSexport const char *const mDNS_DomainTypeNames[] =
1804*4b22b933Srs200217 {
1805*4b22b933Srs200217 "b._dns-sd._udp.", // Browse
1806*4b22b933Srs200217 "db._dns-sd._udp.", // Default Browse
1807*4b22b933Srs200217 "lb._dns-sd._udp.", // Legacy Browse
1808*4b22b933Srs200217 "r._dns-sd._udp.", // Registration
1809*4b22b933Srs200217 "dr._dns-sd._udp." // Default Registration
1810*4b22b933Srs200217 };
1811*4b22b933Srs200217
1812*4b22b933Srs200217 #ifdef UNICAST_DISABLED
1813*4b22b933Srs200217 #define uDNS_IsActiveQuery(q, u) mDNSfalse
1814*4b22b933Srs200217 #endif
1815*4b22b933Srs200217
1816*4b22b933Srs200217 // ***************************************************************************
1817*4b22b933Srs200217 #if COMPILER_LIKES_PRAGMA_MARK
1818*4b22b933Srs200217 #pragma mark -
1819*4b22b933Srs200217 #pragma mark - Specialized mDNS version of vsnprintf
1820*4b22b933Srs200217 #endif
1821*4b22b933Srs200217
1822*4b22b933Srs200217 static const struct mDNSprintf_format
1823*4b22b933Srs200217 {
1824*4b22b933Srs200217 unsigned leftJustify : 1;
1825*4b22b933Srs200217 unsigned forceSign : 1;
1826*4b22b933Srs200217 unsigned zeroPad : 1;
1827*4b22b933Srs200217 unsigned havePrecision : 1;
1828*4b22b933Srs200217 unsigned hSize : 1;
1829*4b22b933Srs200217 unsigned lSize : 1;
1830*4b22b933Srs200217 char altForm;
1831*4b22b933Srs200217 char sign; // +, - or space
1832*4b22b933Srs200217 unsigned int fieldWidth;
1833*4b22b933Srs200217 unsigned int precision;
1834*4b22b933Srs200217 } mDNSprintf_format_default = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
1835*4b22b933Srs200217
mDNS_vsnprintf(char * sbuffer,mDNSu32 buflen,const char * fmt,va_list arg)1836*4b22b933Srs200217 mDNSexport mDNSu32 mDNS_vsnprintf(char *sbuffer, mDNSu32 buflen, const char *fmt, va_list arg)
1837*4b22b933Srs200217 {
1838*4b22b933Srs200217 mDNSu32 nwritten = 0;
1839*4b22b933Srs200217 int c;
1840*4b22b933Srs200217 if (buflen == 0) return(0);
1841*4b22b933Srs200217 buflen--; // Pre-reserve one space in the buffer for the terminating null
1842*4b22b933Srs200217 if (buflen == 0) goto exit;
1843*4b22b933Srs200217
1844*4b22b933Srs200217 for (c = *fmt; c != 0; c = *++fmt)
1845*4b22b933Srs200217 {
1846*4b22b933Srs200217 if (c != '%')
1847*4b22b933Srs200217 {
1848*4b22b933Srs200217 *sbuffer++ = (char)c;
1849*4b22b933Srs200217 if (++nwritten >= buflen) goto exit;
1850*4b22b933Srs200217 }
1851*4b22b933Srs200217 else
1852*4b22b933Srs200217 {
1853*4b22b933Srs200217 unsigned int i=0, j;
1854*4b22b933Srs200217 // The mDNS Vsprintf Argument Conversion Buffer is used as a temporary holding area for
1855*4b22b933Srs200217 // generating decimal numbers, hexdecimal numbers, IP addresses, domain name strings, etc.
1856*4b22b933Srs200217 // The size needs to be enough for a 256-byte domain name plus some error text.
1857*4b22b933Srs200217 #define mDNS_VACB_Size 300
1858*4b22b933Srs200217 char mDNS_VACB[mDNS_VACB_Size];
1859*4b22b933Srs200217 #define mDNS_VACB_Lim (&mDNS_VACB[mDNS_VACB_Size])
1860*4b22b933Srs200217 #define mDNS_VACB_Remain(s) ((mDNSu32)(mDNS_VACB_Lim - s))
1861*4b22b933Srs200217 char *s = mDNS_VACB_Lim, *digits;
1862*4b22b933Srs200217 struct mDNSprintf_format F = mDNSprintf_format_default;
1863*4b22b933Srs200217
1864*4b22b933Srs200217 while (1) // decode flags
1865*4b22b933Srs200217 {
1866*4b22b933Srs200217 c = *++fmt;
1867*4b22b933Srs200217 if (c == '-') F.leftJustify = 1;
1868*4b22b933Srs200217 else if (c == '+') F.forceSign = 1;
1869*4b22b933Srs200217 else if (c == ' ') F.sign = ' ';
1870*4b22b933Srs200217 else if (c == '#') F.altForm++;
1871*4b22b933Srs200217 else if (c == '0') F.zeroPad = 1;
1872*4b22b933Srs200217 else break;
1873*4b22b933Srs200217 }
1874*4b22b933Srs200217
1875*4b22b933Srs200217 if (c == '*') // decode field width
1876*4b22b933Srs200217 {
1877*4b22b933Srs200217 int f = va_arg(arg, int);
1878*4b22b933Srs200217 if (f < 0) { f = -f; F.leftJustify = 1; }
1879*4b22b933Srs200217 F.fieldWidth = (unsigned int)f;
1880*4b22b933Srs200217 c = *++fmt;
1881*4b22b933Srs200217 }
1882*4b22b933Srs200217 else
1883*4b22b933Srs200217 {
1884*4b22b933Srs200217 for (; c >= '0' && c <= '9'; c = *++fmt)
1885*4b22b933Srs200217 F.fieldWidth = (10 * F.fieldWidth) + (c - '0');
1886*4b22b933Srs200217 }
1887*4b22b933Srs200217
1888*4b22b933Srs200217 if (c == '.') // decode precision
1889*4b22b933Srs200217 {
1890*4b22b933Srs200217 if ((c = *++fmt) == '*')
1891*4b22b933Srs200217 { F.precision = va_arg(arg, unsigned int); c = *++fmt; }
1892*4b22b933Srs200217 else for (; c >= '0' && c <= '9'; c = *++fmt)
1893*4b22b933Srs200217 F.precision = (10 * F.precision) + (c - '0');
1894*4b22b933Srs200217 F.havePrecision = 1;
1895*4b22b933Srs200217 }
1896*4b22b933Srs200217
1897*4b22b933Srs200217 if (F.leftJustify) F.zeroPad = 0;
1898*4b22b933Srs200217
1899*4b22b933Srs200217 conv:
1900*4b22b933Srs200217 switch (c) // perform appropriate conversion
1901*4b22b933Srs200217 {
1902*4b22b933Srs200217 unsigned long n;
1903*4b22b933Srs200217 case 'h' : F.hSize = 1; c = *++fmt; goto conv;
1904*4b22b933Srs200217 case 'l' : // fall through
1905*4b22b933Srs200217 case 'L' : F.lSize = 1; c = *++fmt; goto conv;
1906*4b22b933Srs200217 case 'd' :
1907*4b22b933Srs200217 case 'i' : if (F.lSize) n = (unsigned long)va_arg(arg, long);
1908*4b22b933Srs200217 else n = (unsigned long)va_arg(arg, int);
1909*4b22b933Srs200217 if (F.hSize) n = (short) n;
1910*4b22b933Srs200217 if ((long) n < 0) { n = (unsigned long)-(long)n; F.sign = '-'; }
1911*4b22b933Srs200217 else if (F.forceSign) F.sign = '+';
1912*4b22b933Srs200217 goto decimal;
1913*4b22b933Srs200217 case 'u' : if (F.lSize) n = va_arg(arg, unsigned long);
1914*4b22b933Srs200217 else n = va_arg(arg, unsigned int);
1915*4b22b933Srs200217 if (F.hSize) n = (unsigned short) n;
1916*4b22b933Srs200217 F.sign = 0;
1917*4b22b933Srs200217 goto decimal;
1918*4b22b933Srs200217 decimal: if (!F.havePrecision)
1919*4b22b933Srs200217 {
1920*4b22b933Srs200217 if (F.zeroPad)
1921*4b22b933Srs200217 {
1922*4b22b933Srs200217 F.precision = F.fieldWidth;
1923*4b22b933Srs200217 if (F.sign) --F.precision;
1924*4b22b933Srs200217 }
1925*4b22b933Srs200217 if (F.precision < 1) F.precision = 1;
1926*4b22b933Srs200217 }
1927*4b22b933Srs200217 if (F.precision > mDNS_VACB_Size - 1)
1928*4b22b933Srs200217 F.precision = mDNS_VACB_Size - 1;
1929*4b22b933Srs200217 for (i = 0; n; n /= 10, i++) *--s = (char)(n % 10 + '0');
1930*4b22b933Srs200217 for (; i < F.precision; i++) *--s = '0';
1931*4b22b933Srs200217 if (F.sign) { *--s = F.sign; i++; }
1932*4b22b933Srs200217 break;
1933*4b22b933Srs200217
1934*4b22b933Srs200217 case 'o' : if (F.lSize) n = va_arg(arg, unsigned long);
1935*4b22b933Srs200217 else n = va_arg(arg, unsigned int);
1936*4b22b933Srs200217 if (F.hSize) n = (unsigned short) n;
1937*4b22b933Srs200217 if (!F.havePrecision)
1938*4b22b933Srs200217 {
1939*4b22b933Srs200217 if (F.zeroPad) F.precision = F.fieldWidth;
1940*4b22b933Srs200217 if (F.precision < 1) F.precision = 1;
1941*4b22b933Srs200217 }
1942*4b22b933Srs200217 if (F.precision > mDNS_VACB_Size - 1)
1943*4b22b933Srs200217 F.precision = mDNS_VACB_Size - 1;
1944*4b22b933Srs200217 for (i = 0; n; n /= 8, i++) *--s = (char)(n % 8 + '0');
1945*4b22b933Srs200217 if (F.altForm && i && *s != '0') { *--s = '0'; i++; }
1946*4b22b933Srs200217 for (; i < F.precision; i++) *--s = '0';
1947*4b22b933Srs200217 break;
1948*4b22b933Srs200217
1949*4b22b933Srs200217 case 'a' : {
1950*4b22b933Srs200217 unsigned char *a = va_arg(arg, unsigned char *);
1951*4b22b933Srs200217 if (!a) { static char emsg[] = "<<NULL>>"; s = emsg; i = sizeof(emsg)-1; }
1952*4b22b933Srs200217 else
1953*4b22b933Srs200217 {
1954*4b22b933Srs200217 s = mDNS_VACB; // Adjust s to point to the start of the buffer, not the end
1955*4b22b933Srs200217 if (F.altForm)
1956*4b22b933Srs200217 {
1957*4b22b933Srs200217 mDNSAddr *ip = (mDNSAddr*)a;
1958*4b22b933Srs200217 switch (ip->type)
1959*4b22b933Srs200217 {
1960*4b22b933Srs200217 case mDNSAddrType_IPv4: F.precision = 4; a = (unsigned char *)&ip->ip.v4; break;
1961*4b22b933Srs200217 case mDNSAddrType_IPv6: F.precision = 16; a = (unsigned char *)&ip->ip.v6; break;
1962*4b22b933Srs200217 default: F.precision = 0; break;
1963*4b22b933Srs200217 }
1964*4b22b933Srs200217 }
1965*4b22b933Srs200217 switch (F.precision)
1966*4b22b933Srs200217 {
1967*4b22b933Srs200217 case 4: i = mDNS_snprintf(mDNS_VACB, sizeof(mDNS_VACB), "%d.%d.%d.%d",
1968*4b22b933Srs200217 a[0], a[1], a[2], a[3]); break;
1969*4b22b933Srs200217 case 6: i = mDNS_snprintf(mDNS_VACB, sizeof(mDNS_VACB), "%02X:%02X:%02X:%02X:%02X:%02X",
1970*4b22b933Srs200217 a[0], a[1], a[2], a[3], a[4], a[5]); break;
1971*4b22b933Srs200217 case 16: i = mDNS_snprintf(mDNS_VACB, sizeof(mDNS_VACB),
1972*4b22b933Srs200217 "%02X%02X:%02X%02X:%02X%02X:%02X%02X:%02X%02X:%02X%02X:%02X%02X:%02X%02X",
1973*4b22b933Srs200217 a[0x0], a[0x1], a[0x2], a[0x3], a[0x4], a[0x5], a[0x6], a[0x7],
1974*4b22b933Srs200217 a[0x8], a[0x9], a[0xA], a[0xB], a[0xC], a[0xD], a[0xE], a[0xF]); break;
1975*4b22b933Srs200217 default: i = mDNS_snprintf(mDNS_VACB, sizeof(mDNS_VACB), "%s", "<< ERROR: Must specify"
1976*4b22b933Srs200217 " address size (i.e. %.4a=IPv4, %.6a=Ethernet, %.16a=IPv6) >>"); break;
1977*4b22b933Srs200217 }
1978*4b22b933Srs200217 }
1979*4b22b933Srs200217 }
1980*4b22b933Srs200217 break;
1981*4b22b933Srs200217
1982*4b22b933Srs200217 case 'p' : F.havePrecision = F.lSize = 1;
1983*4b22b933Srs200217 F.precision = 8;
1984*4b22b933Srs200217 case 'X' : digits = "0123456789ABCDEF";
1985*4b22b933Srs200217 goto hexadecimal;
1986*4b22b933Srs200217 case 'x' : digits = "0123456789abcdef";
1987*4b22b933Srs200217 hexadecimal:if (F.lSize) n = va_arg(arg, unsigned long);
1988*4b22b933Srs200217 else n = va_arg(arg, unsigned int);
1989*4b22b933Srs200217 if (F.hSize) n = (unsigned short) n;
1990*4b22b933Srs200217 if (!F.havePrecision)
1991*4b22b933Srs200217 {
1992*4b22b933Srs200217 if (F.zeroPad)
1993*4b22b933Srs200217 {
1994*4b22b933Srs200217 F.precision = F.fieldWidth;
1995*4b22b933Srs200217 if (F.altForm) F.precision -= 2;
1996*4b22b933Srs200217 }
1997*4b22b933Srs200217 if (F.precision < 1) F.precision = 1;
1998*4b22b933Srs200217 }
1999*4b22b933Srs200217 if (F.precision > mDNS_VACB_Size - 1)
2000*4b22b933Srs200217 F.precision = mDNS_VACB_Size - 1;
2001*4b22b933Srs200217 for (i = 0; n; n /= 16, i++) *--s = digits[n % 16];
2002*4b22b933Srs200217 for (; i < F.precision; i++) *--s = '0';
2003*4b22b933Srs200217 if (F.altForm) { *--s = (char)c; *--s = '0'; i += 2; }
2004*4b22b933Srs200217 break;
2005*4b22b933Srs200217
2006*4b22b933Srs200217 case 'c' : *--s = (char)va_arg(arg, int); i = 1; break;
2007*4b22b933Srs200217
2008*4b22b933Srs200217 case 's' : s = va_arg(arg, char *);
2009*4b22b933Srs200217 if (!s) { static char emsg[] = "<<NULL>>"; s = emsg; i = sizeof(emsg)-1; }
2010*4b22b933Srs200217 else switch (F.altForm)
2011*4b22b933Srs200217 {
2012*4b22b933Srs200217 case 0: i=0;
2013*4b22b933Srs200217 if (!F.havePrecision) // C string
2014*4b22b933Srs200217 while(s[i]) i++;
2015*4b22b933Srs200217 else
2016*4b22b933Srs200217 {
2017*4b22b933Srs200217 while ((i < F.precision) && s[i]) i++;
2018*4b22b933Srs200217 // Make sure we don't truncate in the middle of a UTF-8 character
2019*4b22b933Srs200217 // If last character we got was any kind of UTF-8 multi-byte character,
2020*4b22b933Srs200217 // then see if we have to back up.
2021*4b22b933Srs200217 // This is not as easy as the similar checks below, because
2022*4b22b933Srs200217 // here we can't assume it's safe to examine the *next* byte, so we
2023*4b22b933Srs200217 // have to confine ourselves to working only backwards in the string.
2024*4b22b933Srs200217 j = i; // Record where we got to
2025*4b22b933Srs200217 // Now, back up until we find first non-continuation-char
2026*4b22b933Srs200217 while (i>0 && (s[i-1] & 0xC0) == 0x80) i--;
2027*4b22b933Srs200217 // Now s[i-1] is the first non-continuation-char
2028*4b22b933Srs200217 // and (j-i) is the number of continuation-chars we found
2029*4b22b933Srs200217 if (i>0 && (s[i-1] & 0xC0) == 0xC0) // If we found a start-char
2030*4b22b933Srs200217 {
2031*4b22b933Srs200217 i--; // Tentatively eliminate this start-char as well
2032*4b22b933Srs200217 // Now (j-i) is the number of characters we're considering eliminating.
2033*4b22b933Srs200217 // To be legal UTF-8, the start-char must contain (j-i) one-bits,
2034*4b22b933Srs200217 // followed by a zero bit. If we shift it right by (7-(j-i)) bits
2035*4b22b933Srs200217 // (with sign extension) then the result has to be 0xFE.
2036*4b22b933Srs200217 // If this is right, then we reinstate the tentatively eliminated bytes.
2037*4b22b933Srs200217 if (((j-i) < 7) && (((s[i] >> (7-(j-i))) & 0xFF) == 0xFE)) i = j;
2038*4b22b933Srs200217 }
2039*4b22b933Srs200217 }
2040*4b22b933Srs200217 break;
2041*4b22b933Srs200217 case 1: i = (unsigned char) *s++; break; // Pascal string
2042*4b22b933Srs200217 case 2: { // DNS label-sequence name
2043*4b22b933Srs200217 unsigned char *a = (unsigned char *)s;
2044*4b22b933Srs200217 s = mDNS_VACB; // Adjust s to point to the start of the buffer, not the end
2045*4b22b933Srs200217 if (*a == 0) *s++ = '.'; // Special case for root DNS name
2046*4b22b933Srs200217 while (*a)
2047*4b22b933Srs200217 {
2048*4b22b933Srs200217 if (*a > 63)
2049*4b22b933Srs200217 { s += mDNS_snprintf(s, mDNS_VACB_Remain(s), "<<INVALID LABEL LENGTH %u>>", *a); break; }
2050*4b22b933Srs200217 if (s + *a >= &mDNS_VACB[254])
2051*4b22b933Srs200217 { s += mDNS_snprintf(s, mDNS_VACB_Remain(s), "<<NAME TOO LONG>>"); break; }
2052*4b22b933Srs200217 s += mDNS_snprintf(s, mDNS_VACB_Remain(s), "%#s.", a);
2053*4b22b933Srs200217 a += 1 + *a;
2054*4b22b933Srs200217 }
2055*4b22b933Srs200217 i = (mDNSu32)(s - mDNS_VACB);
2056*4b22b933Srs200217 s = mDNS_VACB; // Reset s back to the start of the buffer
2057*4b22b933Srs200217 break;
2058*4b22b933Srs200217 }
2059*4b22b933Srs200217 }
2060*4b22b933Srs200217 // Make sure we don't truncate in the middle of a UTF-8 character (see similar comment below)
2061*4b22b933Srs200217 if (F.havePrecision && i > F.precision)
2062*4b22b933Srs200217 { i = F.precision; while (i>0 && (s[i] & 0xC0) == 0x80) i--; }
2063*4b22b933Srs200217 break;
2064*4b22b933Srs200217
2065*4b22b933Srs200217 case 'n' : s = va_arg(arg, char *);
2066*4b22b933Srs200217 if (F.hSize) * (short *) s = (short)nwritten;
2067*4b22b933Srs200217 else if (F.lSize) * (long *) s = (long)nwritten;
2068*4b22b933Srs200217 else * (int *) s = (int)nwritten;
2069*4b22b933Srs200217 continue;
2070*4b22b933Srs200217
2071*4b22b933Srs200217 default: s = mDNS_VACB;
2072*4b22b933Srs200217 i = mDNS_snprintf(mDNS_VACB, sizeof(mDNS_VACB), "<<UNKNOWN FORMAT CONVERSION CODE %%%c>>", c);
2073*4b22b933Srs200217
2074*4b22b933Srs200217 case '%' : *sbuffer++ = (char)c;
2075*4b22b933Srs200217 if (++nwritten >= buflen) goto exit;
2076*4b22b933Srs200217 break;
2077*4b22b933Srs200217 }
2078*4b22b933Srs200217
2079*4b22b933Srs200217 if (i < F.fieldWidth && !F.leftJustify) // Pad on the left
2080*4b22b933Srs200217 do {
2081*4b22b933Srs200217 *sbuffer++ = ' ';
2082*4b22b933Srs200217 if (++nwritten >= buflen) goto exit;
2083*4b22b933Srs200217 } while (i < --F.fieldWidth);
2084*4b22b933Srs200217
2085*4b22b933Srs200217 // Make sure we don't truncate in the middle of a UTF-8 character.
2086*4b22b933Srs200217 // Note: s[i] is the first eliminated character; i.e. the next character *after* the last character of the
2087*4b22b933Srs200217 // allowed output. If s[i] is a UTF-8 continuation character, then we've cut a unicode character in half,
2088*4b22b933Srs200217 // so back up 'i' until s[i] is no longer a UTF-8 continuation character. (if the input was proprly
2089*4b22b933Srs200217 // formed, s[i] will now be the UTF-8 start character of the multi-byte character we just eliminated).
2090*4b22b933Srs200217 if (i > buflen - nwritten)
2091*4b22b933Srs200217 { i = buflen - nwritten; while (i>0 && (s[i] & 0xC0) == 0x80) i--; }
2092*4b22b933Srs200217 for (j=0; j<i; j++) *sbuffer++ = *s++; // Write the converted result
2093*4b22b933Srs200217 nwritten += i;
2094*4b22b933Srs200217 if (nwritten >= buflen) goto exit;
2095*4b22b933Srs200217
2096*4b22b933Srs200217 for (; i < F.fieldWidth; i++) // Pad on the right
2097*4b22b933Srs200217 {
2098*4b22b933Srs200217 *sbuffer++ = ' ';
2099*4b22b933Srs200217 if (++nwritten >= buflen) goto exit;
2100*4b22b933Srs200217 }
2101*4b22b933Srs200217 }
2102*4b22b933Srs200217 }
2103*4b22b933Srs200217 exit:
2104*4b22b933Srs200217 *sbuffer++ = 0;
2105*4b22b933Srs200217 return(nwritten);
2106*4b22b933Srs200217 }
2107*4b22b933Srs200217
mDNS_snprintf(char * sbuffer,mDNSu32 buflen,const char * fmt,...)2108*4b22b933Srs200217 mDNSexport mDNSu32 mDNS_snprintf(char *sbuffer, mDNSu32 buflen, const char *fmt, ...)
2109*4b22b933Srs200217 {
2110*4b22b933Srs200217 mDNSu32 length;
2111*4b22b933Srs200217
2112*4b22b933Srs200217 va_list ptr;
2113*4b22b933Srs200217 va_start(ptr,fmt);
2114*4b22b933Srs200217 length = mDNS_vsnprintf(sbuffer, buflen, fmt, ptr);
2115*4b22b933Srs200217 va_end(ptr);
2116*4b22b933Srs200217
2117*4b22b933Srs200217 return(length);
2118*4b22b933Srs200217 }
2119*4b22b933Srs200217
2120*4b22b933Srs200217 // ***************************************************************************
2121*4b22b933Srs200217 #if COMPILER_LIKES_PRAGMA_MARK
2122*4b22b933Srs200217 #pragma mark -
2123*4b22b933Srs200217 #pragma mark - General Utility Functions
2124*4b22b933Srs200217 #endif
2125*4b22b933Srs200217
2126*4b22b933Srs200217 #define InitialQuestionInterval (mDNSPlatformOneSecond/2)
2127*4b22b933Srs200217 #define ActiveQuestion(Q) ((Q)->ThisQInterval > 0 && !(Q)->DuplicateOf)
2128*4b22b933Srs200217 #define TimeToSendThisQuestion(Q,time) (ActiveQuestion(Q) && (time) - ((Q)->LastQTime + (Q)->ThisQInterval) >= 0)
2129*4b22b933Srs200217
SetNextQueryTime(mDNS * const m,const DNSQuestion * const q)2130*4b22b933Srs200217 mDNSlocal void SetNextQueryTime(mDNS *const m, const DNSQuestion *const q)
2131*4b22b933Srs200217 {
2132*4b22b933Srs200217 if (ActiveQuestion(q))
2133*4b22b933Srs200217 if (m->NextScheduledQuery - (q->LastQTime + q->ThisQInterval) > 0)
2134*4b22b933Srs200217 m->NextScheduledQuery = (q->LastQTime + q->ThisQInterval);
2135*4b22b933Srs200217 }
2136*4b22b933Srs200217
CacheGroupForName(const mDNS * const m,const mDNSu32 slot,const mDNSu32 namehash,const domainname * const name)2137*4b22b933Srs200217 mDNSlocal CacheGroup *CacheGroupForName(const mDNS *const m, const mDNSu32 slot, const mDNSu32 namehash, const domainname *const name)
2138*4b22b933Srs200217 {
2139*4b22b933Srs200217 CacheGroup *cg;
2140*4b22b933Srs200217 for (cg = m->rrcache_hash[slot]; cg; cg=cg->next)
2141*4b22b933Srs200217 if (cg->namehash == namehash && SameDomainName(cg->name, name))
2142*4b22b933Srs200217 break;
2143*4b22b933Srs200217 return(cg);
2144*4b22b933Srs200217 }
2145*4b22b933Srs200217
CacheGroupForRecord(const mDNS * const m,const mDNSu32 slot,const ResourceRecord * const rr)2146*4b22b933Srs200217 mDNSlocal CacheGroup *CacheGroupForRecord(const mDNS *const m, const mDNSu32 slot, const ResourceRecord *const rr)
2147*4b22b933Srs200217 {
2148*4b22b933Srs200217 return(CacheGroupForName(m, slot, rr->namehash, rr->name));
2149*4b22b933Srs200217 }
2150*4b22b933Srs200217
AddressIsLocalSubnet(mDNS * const m,const mDNSInterfaceID InterfaceID,const mDNSAddr * addr)2151*4b22b933Srs200217 mDNSlocal mDNSBool AddressIsLocalSubnet(mDNS *const m, const mDNSInterfaceID InterfaceID, const mDNSAddr *addr)
2152*4b22b933Srs200217 {
2153*4b22b933Srs200217 NetworkInterfaceInfo *intf;
2154*4b22b933Srs200217
2155*4b22b933Srs200217 if (addr->type == mDNSAddrType_IPv4)
2156*4b22b933Srs200217 {
2157*4b22b933Srs200217 if (addr->ip.v4.b[0] == 169 && addr->ip.v4.b[1] == 254) return(mDNStrue);
2158*4b22b933Srs200217 for (intf = m->HostInterfaces; intf; intf = intf->next)
2159*4b22b933Srs200217 if (intf->ip.type == addr->type && intf->InterfaceID == InterfaceID && intf->McastTxRx)
2160*4b22b933Srs200217 if (((intf->ip.ip.v4.NotAnInteger ^ addr->ip.v4.NotAnInteger) & intf->mask.ip.v4.NotAnInteger) == 0)
2161*4b22b933Srs200217 return(mDNStrue);
2162*4b22b933Srs200217 }
2163*4b22b933Srs200217
2164*4b22b933Srs200217 if (addr->type == mDNSAddrType_IPv6)
2165*4b22b933Srs200217 {
2166*4b22b933Srs200217 if (addr->ip.v6.b[0] == 0xFE && addr->ip.v6.b[1] == 0x80) return(mDNStrue);
2167*4b22b933Srs200217 for (intf = m->HostInterfaces; intf; intf = intf->next)
2168*4b22b933Srs200217 if (intf->ip.type == addr->type && intf->InterfaceID == InterfaceID && intf->McastTxRx)
2169*4b22b933Srs200217 if ((((intf->ip.ip.v6.l[0] ^ addr->ip.v6.l[0]) & intf->mask.ip.v6.l[0]) == 0) &&
2170*4b22b933Srs200217 (((intf->ip.ip.v6.l[1] ^ addr->ip.v6.l[1]) & intf->mask.ip.v6.l[1]) == 0) &&
2171*4b22b933Srs200217 (((intf->ip.ip.v6.l[2] ^ addr->ip.v6.l[2]) & intf->mask.ip.v6.l[2]) == 0) &&
2172*4b22b933Srs200217 (((intf->ip.ip.v6.l[3] ^ addr->ip.v6.l[3]) & intf->mask.ip.v6.l[3]) == 0))
2173*4b22b933Srs200217 return(mDNStrue);
2174*4b22b933Srs200217 }
2175*4b22b933Srs200217
2176*4b22b933Srs200217 return(mDNSfalse);
2177*4b22b933Srs200217 }
2178*4b22b933Srs200217
2179*4b22b933Srs200217 // Set up a AuthRecord with sensible default values.
2180*4b22b933Srs200217 // These defaults may be overwritten with new values before mDNS_Register is called
mDNS_SetupResourceRecord(AuthRecord * rr,RData * RDataStorage,mDNSInterfaceID InterfaceID,mDNSu16 rrtype,mDNSu32 ttl,mDNSu8 RecordType,mDNSRecordCallback Callback,void * Context)2181*4b22b933Srs200217 mDNSexport void mDNS_SetupResourceRecord(AuthRecord *rr, RData *RDataStorage, mDNSInterfaceID InterfaceID,
2182*4b22b933Srs200217 mDNSu16 rrtype, mDNSu32 ttl, mDNSu8 RecordType, mDNSRecordCallback Callback, void *Context)
2183*4b22b933Srs200217 {
2184*4b22b933Srs200217 mDNSPlatformMemZero(&rr->uDNS_info, sizeof(uDNS_RegInfo));
2185*4b22b933Srs200217 // Don't try to store a TTL bigger than we can represent in platform time units
2186*4b22b933Srs200217 if (ttl > 0x7FFFFFFFUL / mDNSPlatformOneSecond)
2187*4b22b933Srs200217 ttl = 0x7FFFFFFFUL / mDNSPlatformOneSecond;
2188*4b22b933Srs200217 else if (ttl == 0) // And Zero TTL is illegal
2189*4b22b933Srs200217 ttl = DefaultTTLforRRType(rrtype);
2190*4b22b933Srs200217
2191*4b22b933Srs200217 // Field Group 1: The actual information pertaining to this resource record
2192*4b22b933Srs200217 rr->resrec.RecordType = RecordType;
2193*4b22b933Srs200217 rr->resrec.InterfaceID = InterfaceID;
2194*4b22b933Srs200217 rr->resrec.name = &rr->namestorage;
2195*4b22b933Srs200217 rr->resrec.rrtype = rrtype;
2196*4b22b933Srs200217 rr->resrec.rrclass = kDNSClass_IN;
2197*4b22b933Srs200217 rr->resrec.rroriginalttl = ttl;
2198*4b22b933Srs200217 // rr->resrec.rdlength = MUST set by client and/or in mDNS_Register_internal
2199*4b22b933Srs200217 // rr->resrec.rdestimate = set in mDNS_Register_internal
2200*4b22b933Srs200217 // rr->resrec.rdata = MUST be set by client
2201*4b22b933Srs200217
2202*4b22b933Srs200217 if (RDataStorage)
2203*4b22b933Srs200217 rr->resrec.rdata = RDataStorage;
2204*4b22b933Srs200217 else
2205*4b22b933Srs200217 {
2206*4b22b933Srs200217 rr->resrec.rdata = &rr->rdatastorage;
2207*4b22b933Srs200217 rr->resrec.rdata->MaxRDLength = sizeof(RDataBody);
2208*4b22b933Srs200217 }
2209*4b22b933Srs200217
2210*4b22b933Srs200217 // Field Group 2: Persistent metadata for Authoritative Records
2211*4b22b933Srs200217 rr->Additional1 = mDNSNULL;
2212*4b22b933Srs200217 rr->Additional2 = mDNSNULL;
2213*4b22b933Srs200217 rr->DependentOn = mDNSNULL;
2214*4b22b933Srs200217 rr->RRSet = mDNSNULL;
2215*4b22b933Srs200217 rr->RecordCallback = Callback;
2216*4b22b933Srs200217 rr->RecordContext = Context;
2217*4b22b933Srs200217
2218*4b22b933Srs200217 rr->HostTarget = mDNSfalse;
2219*4b22b933Srs200217 rr->AllowRemoteQuery = mDNSfalse;
2220*4b22b933Srs200217 rr->ForceMCast = mDNSfalse;
2221*4b22b933Srs200217
2222*4b22b933Srs200217 // Field Group 3: Transient state for Authoritative Records (set in mDNS_Register_internal)
2223*4b22b933Srs200217
2224*4b22b933Srs200217 rr->namestorage.c[0] = 0; // MUST be set by client before calling mDNS_Register()
2225*4b22b933Srs200217 }
2226*4b22b933Srs200217
2227*4b22b933Srs200217 // For a single given DNSQuestion, deliver an add/remove result for the single given AuthRecord
2228*4b22b933Srs200217 // Used by AnswerLocalQuestions() and AnswerNewLocalOnlyQuestion()
AnswerLocalOnlyQuestionWithResourceRecord(mDNS * const m,DNSQuestion * q,AuthRecord * rr,mDNSBool AddRecord)2229*4b22b933Srs200217 mDNSlocal void AnswerLocalOnlyQuestionWithResourceRecord(mDNS *const m, DNSQuestion *q, AuthRecord *rr, mDNSBool AddRecord)
2230*4b22b933Srs200217 {
2231*4b22b933Srs200217 // Indicate that we've given at least one positive answer for this record, so we should be prepared to send a goodbye for it
2232*4b22b933Srs200217 if (AddRecord) rr->LocalAnswer = mDNStrue;
2233*4b22b933Srs200217 m->mDNS_reentrancy++; // Increment to allow client to legally make mDNS API calls from the callback
2234*4b22b933Srs200217 if (q->QuestionCallback)
2235*4b22b933Srs200217 q->QuestionCallback(m, q, &rr->resrec, AddRecord);
2236*4b22b933Srs200217 m->mDNS_reentrancy--; // Decrement to block mDNS API calls again
2237*4b22b933Srs200217 }
2238*4b22b933Srs200217
2239*4b22b933Srs200217 // When a new local AuthRecord is created or deleted, AnswerLocalQuestions() runs though our LocalOnlyQuestions delivering answers
2240*4b22b933Srs200217 // to each, stopping if it reaches a NewLocalOnlyQuestion -- brand-new questions are handled by AnswerNewLocalOnlyQuestion().
2241*4b22b933Srs200217 // If the AuthRecord is marked mDNSInterface_LocalOnly, then we also deliver it to any other questions we have using mDNSInterface_Any.
2242*4b22b933Srs200217 // Used by AnswerForNewLocalRecords() and mDNS_Deregister_internal()
AnswerLocalQuestions(mDNS * const m,AuthRecord * rr,mDNSBool AddRecord)2243*4b22b933Srs200217 mDNSlocal void AnswerLocalQuestions(mDNS *const m, AuthRecord *rr, mDNSBool AddRecord)
2244*4b22b933Srs200217 {
2245*4b22b933Srs200217 if (m->CurrentQuestion) LogMsg("AnswerLocalQuestions ERROR m->CurrentQuestion already set");
2246*4b22b933Srs200217
2247*4b22b933Srs200217 m->CurrentQuestion = m->LocalOnlyQuestions;
2248*4b22b933Srs200217 while (m->CurrentQuestion && m->CurrentQuestion != m->NewLocalOnlyQuestions)
2249*4b22b933Srs200217 {
2250*4b22b933Srs200217 DNSQuestion *q = m->CurrentQuestion;
2251*4b22b933Srs200217 m->CurrentQuestion = q->next;
2252*4b22b933Srs200217 if (ResourceRecordAnswersQuestion(&rr->resrec, q))
2253*4b22b933Srs200217 AnswerLocalOnlyQuestionWithResourceRecord(m, q, rr, AddRecord); // MUST NOT dereference q again
2254*4b22b933Srs200217 }
2255*4b22b933Srs200217
2256*4b22b933Srs200217 // If this AuthRecord is marked LocalOnly, then we want to deliver it to all local 'mDNSInterface_Any' questions
2257*4b22b933Srs200217 if (rr->resrec.InterfaceID == mDNSInterface_LocalOnly)
2258*4b22b933Srs200217 {
2259*4b22b933Srs200217 m->CurrentQuestion = m->Questions;
2260*4b22b933Srs200217 while (m->CurrentQuestion && m->CurrentQuestion != m->NewQuestions)
2261*4b22b933Srs200217 {
2262*4b22b933Srs200217 DNSQuestion *q = m->CurrentQuestion;
2263*4b22b933Srs200217 m->CurrentQuestion = q->next;
2264*4b22b933Srs200217 if (ResourceRecordAnswersQuestion(&rr->resrec, q))
2265*4b22b933Srs200217 AnswerLocalOnlyQuestionWithResourceRecord(m, q, rr, AddRecord); // MUST NOT dereference q again
2266*4b22b933Srs200217 }
2267*4b22b933Srs200217 }
2268*4b22b933Srs200217
2269*4b22b933Srs200217 m->CurrentQuestion = mDNSNULL;
2270*4b22b933Srs200217 }
2271*4b22b933Srs200217
2272*4b22b933Srs200217 // ***************************************************************************
2273*4b22b933Srs200217 #if COMPILER_LIKES_PRAGMA_MARK
2274*4b22b933Srs200217 #pragma mark -
2275*4b22b933Srs200217 #pragma mark - Resource Record Utility Functions
2276*4b22b933Srs200217 #endif
2277*4b22b933Srs200217
2278*4b22b933Srs200217 #define RRTypeIsAddressType(T) ((T) == kDNSType_A || (T) == kDNSType_AAAA)
2279*4b22b933Srs200217
2280*4b22b933Srs200217 #define ResourceRecordIsValidAnswer(RR) ( ((RR)-> resrec.RecordType & kDNSRecordTypeActiveMask) && \
2281*4b22b933Srs200217 ((RR)->Additional1 == mDNSNULL || ((RR)->Additional1->resrec.RecordType & kDNSRecordTypeActiveMask)) && \
2282*4b22b933Srs200217 ((RR)->Additional2 == mDNSNULL || ((RR)->Additional2->resrec.RecordType & kDNSRecordTypeActiveMask)) && \
2283*4b22b933Srs200217 ((RR)->DependentOn == mDNSNULL || ((RR)->DependentOn->resrec.RecordType & kDNSRecordTypeActiveMask)) )
2284*4b22b933Srs200217
2285*4b22b933Srs200217 #define ResourceRecordIsValidInterfaceAnswer(RR, INTID) \
2286*4b22b933Srs200217 (ResourceRecordIsValidAnswer(RR) && \
2287*4b22b933Srs200217 ((RR)->resrec.InterfaceID == mDNSInterface_Any || (RR)->resrec.InterfaceID == (INTID)))
2288*4b22b933Srs200217
2289*4b22b933Srs200217 #define DefaultProbeCountForTypeUnique ((mDNSu8)3)
2290*4b22b933Srs200217 #define DefaultProbeCountForRecordType(X) ((X) == kDNSRecordTypeUnique ? DefaultProbeCountForTypeUnique : (mDNSu8)0)
2291*4b22b933Srs200217
2292*4b22b933Srs200217 #define InitialAnnounceCount ((mDNSu8)10)
2293*4b22b933Srs200217
2294*4b22b933Srs200217 // Note that the announce intervals use exponential backoff, doubling each time. The probe intervals do not.
2295*4b22b933Srs200217 // This means that because the announce interval is doubled after sending the first packet, the first
2296*4b22b933Srs200217 // observed on-the-wire inter-packet interval between announcements is actually one second.
2297*4b22b933Srs200217 // The half-second value here may be thought of as a conceptual (non-existent) half-second delay *before* the first packet is sent.
2298*4b22b933Srs200217 #define DefaultProbeIntervalForTypeUnique (mDNSPlatformOneSecond/4)
2299*4b22b933Srs200217 #define DefaultAnnounceIntervalForTypeShared (mDNSPlatformOneSecond/2)
2300*4b22b933Srs200217 #define DefaultAnnounceIntervalForTypeUnique (mDNSPlatformOneSecond/2)
2301*4b22b933Srs200217
2302*4b22b933Srs200217 #define DefaultAPIntervalForRecordType(X) ((X) & (kDNSRecordTypeAdvisory | kDNSRecordTypeShared ) ? DefaultAnnounceIntervalForTypeShared : \
2303*4b22b933Srs200217 (X) & (kDNSRecordTypeUnique ) ? DefaultProbeIntervalForTypeUnique : \
2304*4b22b933Srs200217 (X) & (kDNSRecordTypeVerified | kDNSRecordTypeKnownUnique) ? DefaultAnnounceIntervalForTypeUnique : 0)
2305*4b22b933Srs200217
2306*4b22b933Srs200217 #define TimeToAnnounceThisRecord(RR,time) ((RR)->AnnounceCount && (time) - ((RR)->LastAPTime + (RR)->ThisAPInterval) >= 0)
2307*4b22b933Srs200217 #define TimeToSendThisRecord(RR,time) ((TimeToAnnounceThisRecord(RR,time) || (RR)->ImmedAnswer) && ResourceRecordIsValidAnswer(RR))
2308*4b22b933Srs200217 #define TicksTTL(RR) ((mDNSs32)(RR)->resrec.rroriginalttl * mDNSPlatformOneSecond)
2309*4b22b933Srs200217 #define RRExpireTime(RR) ((RR)->TimeRcvd + TicksTTL(RR))
2310*4b22b933Srs200217
2311*4b22b933Srs200217 #define MaxUnansweredQueries 4
2312*4b22b933Srs200217
2313*4b22b933Srs200217 // SameResourceRecordSignature returns true if two resources records have the same name, type, and class, and may be sent
2314*4b22b933Srs200217 // (or were received) on the same interface (i.e. if *both* records specify an interface, then it has to match).
2315*4b22b933Srs200217 // TTL and rdata may differ.
2316*4b22b933Srs200217 // This is used for cache flush management:
2317*4b22b933Srs200217 // When sending a unique record, all other records matching "SameResourceRecordSignature" must also be sent
2318*4b22b933Srs200217 // When receiving a unique record, all old cache records matching "SameResourceRecordSignature" are flushed
SameResourceRecordSignature(const ResourceRecord * const r1,const ResourceRecord * const r2)2319*4b22b933Srs200217 mDNSlocal mDNSBool SameResourceRecordSignature(const ResourceRecord *const r1, const ResourceRecord *const r2)
2320*4b22b933Srs200217 {
2321*4b22b933Srs200217 if (!r1) { LogMsg("SameResourceRecordSignature ERROR: r1 is NULL"); return(mDNSfalse); }
2322*4b22b933Srs200217 if (!r2) { LogMsg("SameResourceRecordSignature ERROR: r2 is NULL"); return(mDNSfalse); }
2323*4b22b933Srs200217 if (r1->InterfaceID &&
2324*4b22b933Srs200217 r2->InterfaceID &&
2325*4b22b933Srs200217 r1->InterfaceID != r2->InterfaceID) return(mDNSfalse);
2326*4b22b933Srs200217 return(mDNSBool)(
2327*4b22b933Srs200217 r1->rrtype == r2->rrtype &&
2328*4b22b933Srs200217 r1->rrclass == r2->rrclass &&
2329*4b22b933Srs200217 r1->namehash == r2->namehash &&
2330*4b22b933Srs200217 SameDomainName(r1->name, r2->name));
2331*4b22b933Srs200217 }
2332*4b22b933Srs200217
2333*4b22b933Srs200217 // PacketRRMatchesSignature behaves as SameResourceRecordSignature, except that types may differ if our
2334*4b22b933Srs200217 // authoratative record is unique (as opposed to shared). For unique records, we are supposed to have
2335*4b22b933Srs200217 // complete ownership of *all* types for this name, so *any* record type with the same name is a conflict.
2336*4b22b933Srs200217 // In addition, when probing we send our questions with the wildcard type kDNSQType_ANY,
2337*4b22b933Srs200217 // so a response of any type should match, even if it is not actually the type the client plans to use.
PacketRRMatchesSignature(const CacheRecord * const pktrr,const AuthRecord * const authrr)2338*4b22b933Srs200217 mDNSlocal mDNSBool PacketRRMatchesSignature(const CacheRecord *const pktrr, const AuthRecord *const authrr)
2339*4b22b933Srs200217 {
2340*4b22b933Srs200217 if (!pktrr) { LogMsg("PacketRRMatchesSignature ERROR: pktrr is NULL"); return(mDNSfalse); }
2341*4b22b933Srs200217 if (!authrr) { LogMsg("PacketRRMatchesSignature ERROR: authrr is NULL"); return(mDNSfalse); }
2342*4b22b933Srs200217 if (pktrr->resrec.InterfaceID &&
2343*4b22b933Srs200217 authrr->resrec.InterfaceID &&
2344*4b22b933Srs200217 pktrr->resrec.InterfaceID != authrr->resrec.InterfaceID) return(mDNSfalse);
2345*4b22b933Srs200217 if (!(authrr->resrec.RecordType & kDNSRecordTypeUniqueMask) && pktrr->resrec.rrtype != authrr->resrec.rrtype) return(mDNSfalse);
2346*4b22b933Srs200217 return(mDNSBool)(
2347*4b22b933Srs200217 pktrr->resrec.rrclass == authrr->resrec.rrclass &&
2348*4b22b933Srs200217 pktrr->resrec.namehash == authrr->resrec.namehash &&
2349*4b22b933Srs200217 SameDomainName(pktrr->resrec.name, authrr->resrec.name));
2350*4b22b933Srs200217 }
2351*4b22b933Srs200217
2352*4b22b933Srs200217 // IdenticalResourceRecord returns true if two resources records have
2353*4b22b933Srs200217 // the same name, type, class, and identical rdata (InterfaceID and TTL may differ)
IdenticalResourceRecord(const ResourceRecord * const r1,const ResourceRecord * const r2)2354*4b22b933Srs200217 mDNSlocal mDNSBool IdenticalResourceRecord(const ResourceRecord *const r1, const ResourceRecord *const r2)
2355*4b22b933Srs200217 {
2356*4b22b933Srs200217 if (!r1) { LogMsg("IdenticalResourceRecord ERROR: r1 is NULL"); return(mDNSfalse); }
2357*4b22b933Srs200217 if (!r2) { LogMsg("IdenticalResourceRecord ERROR: r2 is NULL"); return(mDNSfalse); }
2358*4b22b933Srs200217 if (r1->rrtype != r2->rrtype || r1->rrclass != r2->rrclass || r1->namehash != r2->namehash || !SameDomainName(r1->name, r2->name))
2359*4b22b933Srs200217 return(mDNSfalse);
2360*4b22b933Srs200217 return(SameRData(r1, r2));
2361*4b22b933Srs200217 }
2362*4b22b933Srs200217
2363*4b22b933Srs200217 // CacheRecord *ks is the CacheRecord from the known answer list in the query.
2364*4b22b933Srs200217 // This is the information that the requester believes to be correct.
2365*4b22b933Srs200217 // AuthRecord *rr is the answer we are proposing to give, if not suppressed.
2366*4b22b933Srs200217 // This is the information that we believe to be correct.
2367*4b22b933Srs200217 // We've already determined that we plan to give this answer on this interface
2368*4b22b933Srs200217 // (either the record is non-specific, or it is specific to this interface)
2369*4b22b933Srs200217 // so now we just need to check the name, type, class, rdata and TTL.
ShouldSuppressKnownAnswer(const CacheRecord * const ka,const AuthRecord * const rr)2370*4b22b933Srs200217 mDNSlocal mDNSBool ShouldSuppressKnownAnswer(const CacheRecord *const ka, const AuthRecord *const rr)
2371*4b22b933Srs200217 {
2372*4b22b933Srs200217 // If RR signature is different, or data is different, then don't suppress our answer
2373*4b22b933Srs200217 if (!IdenticalResourceRecord(&ka->resrec, &rr->resrec)) return(mDNSfalse);
2374*4b22b933Srs200217
2375*4b22b933Srs200217 // If the requester's indicated TTL is less than half the real TTL,
2376*4b22b933Srs200217 // we need to give our answer before the requester's copy expires.
2377*4b22b933Srs200217 // If the requester's indicated TTL is at least half the real TTL,
2378*4b22b933Srs200217 // then we can suppress our answer this time.
2379*4b22b933Srs200217 // If the requester's indicated TTL is greater than the TTL we believe,
2380*4b22b933Srs200217 // then that's okay, and we don't need to do anything about it.
2381*4b22b933Srs200217 // (If two responders on the network are offering the same information,
2382*4b22b933Srs200217 // that's okay, and if they are offering the information with different TTLs,
2383*4b22b933Srs200217 // the one offering the lower TTL should defer to the one offering the higher TTL.)
2384*4b22b933Srs200217 return(mDNSBool)(ka->resrec.rroriginalttl >= rr->resrec.rroriginalttl / 2);
2385*4b22b933Srs200217 }
2386*4b22b933Srs200217
SetNextAnnounceProbeTime(mDNS * const m,const AuthRecord * const rr)2387*4b22b933Srs200217 mDNSlocal void SetNextAnnounceProbeTime(mDNS *const m, const AuthRecord *const rr)
2388*4b22b933Srs200217 {
2389*4b22b933Srs200217 if (rr->resrec.RecordType == kDNSRecordTypeUnique)
2390*4b22b933Srs200217 {
2391*4b22b933Srs200217 //LogMsg("ProbeCount %d Next %ld %s",
2392*4b22b933Srs200217 // rr->ProbeCount, (rr->LastAPTime + rr->ThisAPInterval) - m->timenow, ARDisplayString(m, rr));
2393*4b22b933Srs200217 if (m->NextScheduledProbe - (rr->LastAPTime + rr->ThisAPInterval) >= 0)
2394*4b22b933Srs200217 m->NextScheduledProbe = (rr->LastAPTime + rr->ThisAPInterval);
2395*4b22b933Srs200217 }
2396*4b22b933Srs200217 else if (rr->AnnounceCount && ResourceRecordIsValidAnswer(rr))
2397*4b22b933Srs200217 {
2398*4b22b933Srs200217 if (m->NextScheduledResponse - (rr->LastAPTime + rr->ThisAPInterval) >= 0)
2399*4b22b933Srs200217 m->NextScheduledResponse = (rr->LastAPTime + rr->ThisAPInterval);
2400*4b22b933Srs200217 }
2401*4b22b933Srs200217 }
2402*4b22b933Srs200217
InitializeLastAPTime(mDNS * const m,AuthRecord * const rr)2403*4b22b933Srs200217 mDNSlocal void InitializeLastAPTime(mDNS *const m, AuthRecord *const rr)
2404*4b22b933Srs200217 {
2405*4b22b933Srs200217 // To allow us to aggregate probes when a group of services are registered together,
2406*4b22b933Srs200217 // the first probe is delayed 1/4 second. This means the common-case behaviour is:
2407*4b22b933Srs200217 // 1/4 second wait; probe
2408*4b22b933Srs200217 // 1/4 second wait; probe
2409*4b22b933Srs200217 // 1/4 second wait; probe
2410*4b22b933Srs200217 // 1/4 second wait; announce (i.e. service is normally announced exactly one second after being registered)
2411*4b22b933Srs200217
2412*4b22b933Srs200217 // If we have no probe suppression time set, or it is in the past, set it now
2413*4b22b933Srs200217 if (m->SuppressProbes == 0 || m->SuppressProbes - m->timenow < 0)
2414*4b22b933Srs200217 {
2415*4b22b933Srs200217 m->SuppressProbes = NonZeroTime(m->timenow + DefaultProbeIntervalForTypeUnique);
2416*4b22b933Srs200217 // If we already have a probe scheduled to go out sooner, then use that time to get better aggregation
2417*4b22b933Srs200217 if (m->SuppressProbes - m->NextScheduledProbe >= 0)
2418*4b22b933Srs200217 m->SuppressProbes = m->NextScheduledProbe;
2419*4b22b933Srs200217 // If we already have a query scheduled to go out sooner, then use that time to get better aggregation
2420*4b22b933Srs200217 if (m->SuppressProbes - m->NextScheduledQuery >= 0)
2421*4b22b933Srs200217 m->SuppressProbes = m->NextScheduledQuery;
2422*4b22b933Srs200217 }
2423*4b22b933Srs200217
2424*4b22b933Srs200217 // We announce to flush stale data from other caches. It is a reasonable assumption that any
2425*4b22b933Srs200217 // old stale copies will probably have the same TTL we're using, so announcing longer than
2426*4b22b933Srs200217 // this serves no purpose -- any stale copies of that record will have expired by then anyway.
2427*4b22b933Srs200217 rr->AnnounceUntil = m->timenow + TicksTTL(rr);
2428*4b22b933Srs200217 rr->LastAPTime = m->SuppressProbes - rr->ThisAPInterval;
2429*4b22b933Srs200217 // Set LastMCTime to now, to inhibit multicast responses
2430*4b22b933Srs200217 // (no need to send additional multicast responses when we're announcing anyway)
2431*4b22b933Srs200217 rr->LastMCTime = m->timenow;
2432*4b22b933Srs200217 rr->LastMCInterface = mDNSInterfaceMark;
2433*4b22b933Srs200217
2434*4b22b933Srs200217 // If this is a record type that's not going to probe, then delay its first announcement so that
2435*4b22b933Srs200217 // it will go out synchronized with the first announcement for the other records that *are* probing.
2436*4b22b933Srs200217 // This is a minor performance tweak that helps keep groups of related records synchronized together.
2437*4b22b933Srs200217 // The addition of "rr->ThisAPInterval / 2" is to make sure that, in the event that any of the probes are
2438*4b22b933Srs200217 // delayed by a few milliseconds, this announcement does not inadvertently go out *before* the probing is complete.
2439*4b22b933Srs200217 // When the probing is complete and those records begin to announce, these records will also be picked up and accelerated,
2440*4b22b933Srs200217 // because they will meet the criterion of being at least half-way to their scheduled announcement time.
2441*4b22b933Srs200217 if (rr->resrec.RecordType != kDNSRecordTypeUnique)
2442*4b22b933Srs200217 rr->LastAPTime += DefaultProbeIntervalForTypeUnique * DefaultProbeCountForTypeUnique + rr->ThisAPInterval / 2;
2443*4b22b933Srs200217
2444*4b22b933Srs200217 SetNextAnnounceProbeTime(m, rr);
2445*4b22b933Srs200217 }
2446*4b22b933Srs200217
2447*4b22b933Srs200217 #define HashSlot(X) (DomainNameHashValue(X) % CACHE_HASH_SLOTS)
2448*4b22b933Srs200217
SetTargetToHostName(mDNS * const m,AuthRecord * const rr)2449*4b22b933Srs200217 mDNSlocal void SetTargetToHostName(mDNS *const m, AuthRecord *const rr)
2450*4b22b933Srs200217 {
2451*4b22b933Srs200217 domainname *target = GetRRDomainNameTarget(&rr->resrec);
2452*4b22b933Srs200217
2453*4b22b933Srs200217 if (!target) debugf("SetTargetToHostName: Don't know how to set the target of rrtype %d", rr->resrec.rrtype);
2454*4b22b933Srs200217
2455*4b22b933Srs200217 if (target && SameDomainName(target, &m->MulticastHostname))
2456*4b22b933Srs200217 debugf("SetTargetToHostName: Target of %##s is already %##s", rr->resrec.name->c, target->c);
2457*4b22b933Srs200217
2458*4b22b933Srs200217 if (target && !SameDomainName(target, &m->MulticastHostname))
2459*4b22b933Srs200217 {
2460*4b22b933Srs200217 AssignDomainName(target, &m->MulticastHostname);
2461*4b22b933Srs200217 SetNewRData(&rr->resrec, mDNSNULL, 0);
2462*4b22b933Srs200217
2463*4b22b933Srs200217 // If we're in the middle of probing this record, we need to start again,
2464*4b22b933Srs200217 // because changing its rdata may change the outcome of the tie-breaker.
2465*4b22b933Srs200217 // (If the record type is kDNSRecordTypeUnique (unconfirmed unique) then DefaultProbeCountForRecordType is non-zero.)
2466*4b22b933Srs200217 rr->ProbeCount = DefaultProbeCountForRecordType(rr->resrec.RecordType);
2467*4b22b933Srs200217
2468*4b22b933Srs200217 // If we've announced this record, we really should send a goodbye packet for the old rdata before
2469*4b22b933Srs200217 // changing to the new rdata. However, in practice, we only do SetTargetToHostName for unique records,
2470*4b22b933Srs200217 // so when we announce them we'll set the kDNSClass_UniqueRRSet and clear any stale data that way.
2471*4b22b933Srs200217 if (rr->RequireGoodbye && rr->resrec.RecordType == kDNSRecordTypeShared)
2472*4b22b933Srs200217 debugf("Have announced shared record %##s (%s) at least once: should have sent a goodbye packet before updating",
2473*4b22b933Srs200217 rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype));
2474*4b22b933Srs200217
2475*4b22b933Srs200217 rr->AnnounceCount = InitialAnnounceCount;
2476*4b22b933Srs200217 rr->RequireGoodbye = mDNSfalse;
2477*4b22b933Srs200217 rr->ThisAPInterval = DefaultAPIntervalForRecordType(rr->resrec.RecordType);
2478*4b22b933Srs200217 InitializeLastAPTime(m,rr);
2479*4b22b933Srs200217 }
2480*4b22b933Srs200217 }
2481*4b22b933Srs200217
AcknowledgeRecord(mDNS * const m,AuthRecord * const rr)2482*4b22b933Srs200217 mDNSlocal void AcknowledgeRecord(mDNS *const m, AuthRecord *const rr)
2483*4b22b933Srs200217 {
2484*4b22b933Srs200217 if (!rr->Acknowledged && rr->RecordCallback)
2485*4b22b933Srs200217 {
2486*4b22b933Srs200217 // CAUTION: MUST NOT do anything more with rr after calling rr->Callback(), because the client's callback function
2487*4b22b933Srs200217 // is allowed to do anything, including starting/stopping queries, registering/deregistering records, etc.
2488*4b22b933Srs200217 rr->Acknowledged = mDNStrue;
2489*4b22b933Srs200217 m->mDNS_reentrancy++; // Increment to allow client to legally make mDNS API calls from the callback
2490*4b22b933Srs200217 rr->RecordCallback(m, rr, mStatus_NoError);
2491*4b22b933Srs200217 m->mDNS_reentrancy--; // Decrement to block mDNS API calls again
2492*4b22b933Srs200217 }
2493*4b22b933Srs200217 }
2494*4b22b933Srs200217
2495*4b22b933Srs200217 // Two records qualify to be local duplicates if the RecordTypes are the same, or if one is Unique and the other Verified
2496*4b22b933Srs200217 #define RecordLDT(A,B) ((A)->resrec.RecordType == (B)->resrec.RecordType || \
2497*4b22b933Srs200217 ((A)->resrec.RecordType | (B)->resrec.RecordType) == (kDNSRecordTypeUnique | kDNSRecordTypeVerified))
2498*4b22b933Srs200217 #define RecordIsLocalDuplicate(A,B) \
2499*4b22b933Srs200217 ((A)->resrec.InterfaceID == (B)->resrec.InterfaceID && RecordLDT((A),(B)) && IdenticalResourceRecord(&(A)->resrec, &(B)->resrec))
2500*4b22b933Srs200217
mDNS_Register_internal(mDNS * const m,AuthRecord * const rr)2501*4b22b933Srs200217 mDNSlocal mStatus mDNS_Register_internal(mDNS *const m, AuthRecord *const rr)
2502*4b22b933Srs200217 {
2503*4b22b933Srs200217 domainname *target = GetRRDomainNameTarget(&rr->resrec);
2504*4b22b933Srs200217 AuthRecord *r;
2505*4b22b933Srs200217 AuthRecord **p = &m->ResourceRecords;
2506*4b22b933Srs200217 AuthRecord **d = &m->DuplicateRecords;
2507*4b22b933Srs200217
2508*4b22b933Srs200217 mDNSPlatformMemZero(&rr->uDNS_info, sizeof(uDNS_RegInfo));
2509*4b22b933Srs200217
2510*4b22b933Srs200217 if ((mDNSs32)rr->resrec.rroriginalttl <= 0)
2511*4b22b933Srs200217 { LogMsg("mDNS_Register_internal: TTL must be 1 - 0x7FFFFFFF %s", ARDisplayString(m, rr)); return(mStatus_BadParamErr); }
2512*4b22b933Srs200217
2513*4b22b933Srs200217 #ifndef UNICAST_DISABLED
2514*4b22b933Srs200217 if (rr->resrec.InterfaceID == mDNSInterface_LocalOnly || rr->ForceMCast || IsLocalDomain(rr->resrec.name))
2515*4b22b933Srs200217 rr->uDNS_info.id = zeroID;
2516*4b22b933Srs200217 else return uDNS_RegisterRecord(m, rr);
2517*4b22b933Srs200217 #endif
2518*4b22b933Srs200217
2519*4b22b933Srs200217 while (*p && *p != rr) p=&(*p)->next;
2520*4b22b933Srs200217 while (*d && *d != rr) d=&(*d)->next;
2521*4b22b933Srs200217 if (*d || *p)
2522*4b22b933Srs200217 {
2523*4b22b933Srs200217 LogMsg("Error! Tried to register a AuthRecord %p %##s (%s) that's already in the list",
2524*4b22b933Srs200217 rr, rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype));
2525*4b22b933Srs200217 return(mStatus_AlreadyRegistered);
2526*4b22b933Srs200217 }
2527*4b22b933Srs200217
2528*4b22b933Srs200217 if (rr->DependentOn)
2529*4b22b933Srs200217 {
2530*4b22b933Srs200217 if (rr->resrec.RecordType == kDNSRecordTypeUnique)
2531*4b22b933Srs200217 rr->resrec.RecordType = kDNSRecordTypeVerified;
2532*4b22b933Srs200217 else
2533*4b22b933Srs200217 {
2534*4b22b933Srs200217 LogMsg("mDNS_Register_internal: ERROR! %##s (%s): rr->DependentOn && RecordType != kDNSRecordTypeUnique",
2535*4b22b933Srs200217 rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype));
2536*4b22b933Srs200217 return(mStatus_Invalid);
2537*4b22b933Srs200217 }
2538*4b22b933Srs200217 if (!(rr->DependentOn->resrec.RecordType & (kDNSRecordTypeUnique | kDNSRecordTypeVerified)))
2539*4b22b933Srs200217 {
2540*4b22b933Srs200217 LogMsg("mDNS_Register_internal: ERROR! %##s (%s): rr->DependentOn->RecordType bad type %X",
2541*4b22b933Srs200217 rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype), rr->DependentOn->resrec.RecordType);
2542*4b22b933Srs200217 return(mStatus_Invalid);
2543*4b22b933Srs200217 }
2544*4b22b933Srs200217 }
2545*4b22b933Srs200217
2546*4b22b933Srs200217 // If this resource record is referencing a specific interface, make sure it exists
2547*4b22b933Srs200217 if (rr->resrec.InterfaceID && rr->resrec.InterfaceID != mDNSInterface_LocalOnly)
2548*4b22b933Srs200217 {
2549*4b22b933Srs200217 NetworkInterfaceInfo *intf;
2550*4b22b933Srs200217 for (intf = m->HostInterfaces; intf; intf = intf->next)
2551*4b22b933Srs200217 if (intf->InterfaceID == rr->resrec.InterfaceID) break;
2552*4b22b933Srs200217 if (!intf)
2553*4b22b933Srs200217 {
2554*4b22b933Srs200217 debugf("mDNS_Register_internal: Bogus InterfaceID %p in resource record", rr->resrec.InterfaceID);
2555*4b22b933Srs200217 return(mStatus_BadReferenceErr);
2556*4b22b933Srs200217 }
2557*4b22b933Srs200217 }
2558*4b22b933Srs200217
2559*4b22b933Srs200217 rr->next = mDNSNULL;
2560*4b22b933Srs200217
2561*4b22b933Srs200217 // Field Group 1: Persistent metadata for Authoritative Records
2562*4b22b933Srs200217 // rr->Additional1 = set to mDNSNULL in mDNS_SetupResourceRecord; may be overridden by client
2563*4b22b933Srs200217 // rr->Additional2 = set to mDNSNULL in mDNS_SetupResourceRecord; may be overridden by client
2564*4b22b933Srs200217 // rr->DependentOn = set to mDNSNULL in mDNS_SetupResourceRecord; may be overridden by client
2565*4b22b933Srs200217 // rr->RRSet = set to mDNSNULL in mDNS_SetupResourceRecord; may be overridden by client
2566*4b22b933Srs200217 // rr->Callback = already set in mDNS_SetupResourceRecord
2567*4b22b933Srs200217 // rr->Context = already set in mDNS_SetupResourceRecord
2568*4b22b933Srs200217 // rr->RecordType = already set in mDNS_SetupResourceRecord
2569*4b22b933Srs200217 // rr->HostTarget = set to mDNSfalse in mDNS_SetupResourceRecord; may be overridden by client
2570*4b22b933Srs200217 // rr->AllowRemoteQuery = set to mDNSfalse in mDNS_SetupResourceRecord; may be overridden by client
2571*4b22b933Srs200217 // Make sure target is not uninitialized data, or we may crash writing debugging log messages
2572*4b22b933Srs200217 if (rr->HostTarget && target) target->c[0] = 0;
2573*4b22b933Srs200217
2574*4b22b933Srs200217 // Field Group 2: Transient state for Authoritative Records
2575*4b22b933Srs200217 rr->Acknowledged = mDNSfalse;
2576*4b22b933Srs200217 rr->ProbeCount = DefaultProbeCountForRecordType(rr->resrec.RecordType);
2577*4b22b933Srs200217 rr->AnnounceCount = InitialAnnounceCount;
2578*4b22b933Srs200217 rr->RequireGoodbye = mDNSfalse;
2579*4b22b933Srs200217 rr->LocalAnswer = mDNSfalse;
2580*4b22b933Srs200217 rr->IncludeInProbe = mDNSfalse;
2581*4b22b933Srs200217 rr->ImmedAnswer = mDNSNULL;
2582*4b22b933Srs200217 rr->ImmedUnicast = mDNSfalse;
2583*4b22b933Srs200217 rr->ImmedAdditional = mDNSNULL;
2584*4b22b933Srs200217 rr->SendRNow = mDNSNULL;
2585*4b22b933Srs200217 rr->v4Requester = zerov4Addr;
2586*4b22b933Srs200217 rr->v6Requester = zerov6Addr;
2587*4b22b933Srs200217 rr->NextResponse = mDNSNULL;
2588*4b22b933Srs200217 rr->NR_AnswerTo = mDNSNULL;
2589*4b22b933Srs200217 rr->NR_AdditionalTo = mDNSNULL;
2590*4b22b933Srs200217 rr->ThisAPInterval = DefaultAPIntervalForRecordType(rr->resrec.RecordType);
2591*4b22b933Srs200217 if (!rr->HostTarget) InitializeLastAPTime(m, rr);
2592*4b22b933Srs200217 // rr->AnnounceUntil = Set for us in InitializeLastAPTime()
2593*4b22b933Srs200217 // rr->LastAPTime = Set for us in InitializeLastAPTime()
2594*4b22b933Srs200217 // rr->LastMCTime = Set for us in InitializeLastAPTime()
2595*4b22b933Srs200217 // rr->LastMCInterface = Set for us in InitializeLastAPTime()
2596*4b22b933Srs200217 rr->NewRData = mDNSNULL;
2597*4b22b933Srs200217 rr->newrdlength = 0;
2598*4b22b933Srs200217 rr->UpdateCallback = mDNSNULL;
2599*4b22b933Srs200217 rr->UpdateCredits = kMaxUpdateCredits;
2600*4b22b933Srs200217 rr->NextUpdateCredit = 0;
2601*4b22b933Srs200217 rr->UpdateBlocked = 0;
2602*4b22b933Srs200217
2603*4b22b933Srs200217 // rr->resrec.interface = already set in mDNS_SetupResourceRecord
2604*4b22b933Srs200217 // rr->resrec.name->c = MUST be set by client
2605*4b22b933Srs200217 // rr->resrec.rrtype = already set in mDNS_SetupResourceRecord
2606*4b22b933Srs200217 // rr->resrec.rrclass = already set in mDNS_SetupResourceRecord
2607*4b22b933Srs200217 // rr->resrec.rroriginalttl = already set in mDNS_SetupResourceRecord
2608*4b22b933Srs200217 // rr->resrec.rdata = MUST be set by client, unless record type is CNAME or PTR and rr->HostTarget is set
2609*4b22b933Srs200217
2610*4b22b933Srs200217 if (rr->HostTarget)
2611*4b22b933Srs200217 SetTargetToHostName(m, rr); // Also sets rdlength and rdestimate for us, and calls InitializeLastAPTime();
2612*4b22b933Srs200217 else
2613*4b22b933Srs200217 {
2614*4b22b933Srs200217 rr->resrec.rdlength = GetRDLength(&rr->resrec, mDNSfalse);
2615*4b22b933Srs200217 rr->resrec.rdestimate = GetRDLength(&rr->resrec, mDNStrue);
2616*4b22b933Srs200217 }
2617*4b22b933Srs200217
2618*4b22b933Srs200217 if (!ValidateDomainName(rr->resrec.name))
2619*4b22b933Srs200217 { LogMsg("Attempt to register record with invalid name: %s", ARDisplayString(m, rr)); return(mStatus_Invalid); }
2620*4b22b933Srs200217
2621*4b22b933Srs200217 // BIND named (name daemon) doesn't allow TXT records with zero-length rdata. This is strictly speaking correct,
2622*4b22b933Srs200217 // since RFC 1035 specifies a TXT record as "One or more <character-string>s", not "Zero or more <character-string>s".
2623*4b22b933Srs200217 // Since some legacy apps try to create zero-length TXT records, we'll silently correct it here.
2624*4b22b933Srs200217 if (rr->resrec.rrtype == kDNSType_TXT && rr->resrec.rdlength == 0) { rr->resrec.rdlength = 1; rr->resrec.rdata->u.txt.c[0] = 0; }
2625*4b22b933Srs200217
2626*4b22b933Srs200217 // Don't do this until *after* we've set rr->resrec.rdlength
2627*4b22b933Srs200217 if (!ValidateRData(rr->resrec.rrtype, rr->resrec.rdlength, rr->resrec.rdata))
2628*4b22b933Srs200217 { LogMsg("Attempt to register record with invalid rdata: %s", ARDisplayString(m, rr)); return(mStatus_Invalid); }
2629*4b22b933Srs200217
2630*4b22b933Srs200217 rr->resrec.namehash = DomainNameHashValue(rr->resrec.name);
2631*4b22b933Srs200217 rr->resrec.rdatahash = target ? DomainNameHashValue(target) : RDataHashValue(rr->resrec.rdlength, &rr->resrec.rdata->u);
2632*4b22b933Srs200217
2633*4b22b933Srs200217 if (rr->resrec.InterfaceID == mDNSInterface_LocalOnly)
2634*4b22b933Srs200217 {
2635*4b22b933Srs200217 // If this is supposed to be unique, make sure we don't have any name conflicts
2636*4b22b933Srs200217 if (rr->resrec.RecordType & kDNSRecordTypeUniqueMask)
2637*4b22b933Srs200217 {
2638*4b22b933Srs200217 const AuthRecord *s1 = rr->RRSet ? rr->RRSet : rr;
2639*4b22b933Srs200217 for (r = m->ResourceRecords; r; r=r->next)
2640*4b22b933Srs200217 {
2641*4b22b933Srs200217 const AuthRecord *s2 = r->RRSet ? r->RRSet : r;
2642*4b22b933Srs200217 if (s1 != s2 && SameResourceRecordSignature(&r->resrec, &rr->resrec) && !SameRData(&r->resrec, &rr->resrec))
2643*4b22b933Srs200217 break;
2644*4b22b933Srs200217 }
2645*4b22b933Srs200217 if (r) // If we found a conflict, set RecordType = kDNSRecordTypeDeregistering so we'll deliver the callback
2646*4b22b933Srs200217 {
2647*4b22b933Srs200217 debugf("Name conflict %p %##s (%s)", rr, rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype));
2648*4b22b933Srs200217 rr->resrec.RecordType = kDNSRecordTypeDeregistering;
2649*4b22b933Srs200217 rr->resrec.rroriginalttl = 0;
2650*4b22b933Srs200217 rr->ImmedAnswer = mDNSInterfaceMark;
2651*4b22b933Srs200217 m->NextScheduledResponse = m->timenow;
2652*4b22b933Srs200217 }
2653*4b22b933Srs200217 }
2654*4b22b933Srs200217 }
2655*4b22b933Srs200217
2656*4b22b933Srs200217 // Now that we've finished building our new record, make sure it's not identical to one we already have
2657*4b22b933Srs200217 for (r = m->ResourceRecords; r; r=r->next) if (RecordIsLocalDuplicate(r, rr)) break;
2658*4b22b933Srs200217
2659*4b22b933Srs200217 if (r)
2660*4b22b933Srs200217 {
2661*4b22b933Srs200217 debugf("Adding to duplicate list %p %s", rr, ARDisplayString(m,rr));
2662*4b22b933Srs200217 *d = rr;
2663*4b22b933Srs200217 // If the previous copy of this record is already verified unique,
2664*4b22b933Srs200217 // then indicate that we should move this record promptly to kDNSRecordTypeUnique state.
2665*4b22b933Srs200217 // Setting ProbeCount to zero will cause SendQueries() to advance this record to
2666*4b22b933Srs200217 // kDNSRecordTypeVerified state and call the client callback at the next appropriate time.
2667*4b22b933Srs200217 if (rr->resrec.RecordType == kDNSRecordTypeUnique && r->resrec.RecordType == kDNSRecordTypeVerified)
2668*4b22b933Srs200217 rr->ProbeCount = 0;
2669*4b22b933Srs200217 }
2670*4b22b933Srs200217 else
2671*4b22b933Srs200217 {
2672*4b22b933Srs200217 debugf("Adding to active record list %p %s", rr, ARDisplayString(m,rr));
2673*4b22b933Srs200217 if (!m->NewLocalRecords) m->NewLocalRecords = rr;
2674*4b22b933Srs200217 *p = rr;
2675*4b22b933Srs200217 }
2676*4b22b933Srs200217
2677*4b22b933Srs200217 // For records that are not going to probe, acknowledge them right away
2678*4b22b933Srs200217 if (rr->resrec.RecordType != kDNSRecordTypeUnique && rr->resrec.RecordType != kDNSRecordTypeDeregistering)
2679*4b22b933Srs200217 AcknowledgeRecord(m, rr);
2680*4b22b933Srs200217
2681*4b22b933Srs200217 return(mStatus_NoError);
2682*4b22b933Srs200217 }
2683*4b22b933Srs200217
RecordProbeFailure(mDNS * const m,const AuthRecord * const rr)2684*4b22b933Srs200217 mDNSlocal void RecordProbeFailure(mDNS *const m, const AuthRecord *const rr)
2685*4b22b933Srs200217 {
2686*4b22b933Srs200217 m->ProbeFailTime = m->timenow;
2687*4b22b933Srs200217 m->NumFailedProbes++;
2688*4b22b933Srs200217 // If we've had fifteen or more probe failures, rate-limit to one every five seconds.
2689*4b22b933Srs200217 // If a bunch of hosts have all been configured with the same name, then they'll all
2690*4b22b933Srs200217 // conflict and run through the same series of names: name-2, name-3, name-4, etc.,
2691*4b22b933Srs200217 // up to name-10. After that they'll start adding random increments in the range 1-100,
2692*4b22b933Srs200217 // so they're more likely to branch out in the available namespace and settle on a set of
2693*4b22b933Srs200217 // unique names quickly. If after five more tries the host is still conflicting, then we
2694*4b22b933Srs200217 // may have a serious problem, so we start rate-limiting so we don't melt down the network.
2695*4b22b933Srs200217 if (m->NumFailedProbes >= 15)
2696*4b22b933Srs200217 {
2697*4b22b933Srs200217 m->SuppressProbes = NonZeroTime(m->timenow + mDNSPlatformOneSecond * 5);
2698*4b22b933Srs200217 LogMsg("Excessive name conflicts (%lu) for %##s (%s); rate limiting in effect",
2699*4b22b933Srs200217 m->NumFailedProbes, rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype));
2700*4b22b933Srs200217 }
2701*4b22b933Srs200217 }
2702*4b22b933Srs200217
CompleteRDataUpdate(mDNS * const m,AuthRecord * const rr)2703*4b22b933Srs200217 mDNSlocal void CompleteRDataUpdate(mDNS *const m, AuthRecord *const rr)
2704*4b22b933Srs200217 {
2705*4b22b933Srs200217 RData *OldRData = rr->resrec.rdata;
2706*4b22b933Srs200217 SetNewRData(&rr->resrec, rr->NewRData, rr->newrdlength); // Update our rdata
2707*4b22b933Srs200217 rr->NewRData = mDNSNULL; // Clear the NewRData pointer ...
2708*4b22b933Srs200217 if (rr->UpdateCallback)
2709*4b22b933Srs200217 rr->UpdateCallback(m, rr, OldRData); // ... and let the client know
2710*4b22b933Srs200217 }
2711*4b22b933Srs200217
2712*4b22b933Srs200217 // mDNS_Dereg_normal is used for most calls to mDNS_Deregister_internal
2713*4b22b933Srs200217 // mDNS_Dereg_conflict is used to indicate that this record is being forcibly deregistered because of a conflict
2714*4b22b933Srs200217 // mDNS_Dereg_repeat is used when cleaning up, for records that may have already been forcibly deregistered
2715*4b22b933Srs200217 typedef enum { mDNS_Dereg_normal, mDNS_Dereg_conflict, mDNS_Dereg_repeat } mDNS_Dereg_type;
2716*4b22b933Srs200217
2717*4b22b933Srs200217 // NOTE: mDNS_Deregister_internal can call a user callback, which may change the record list and/or question list.
2718*4b22b933Srs200217 // Any code walking either list must use the CurrentQuestion and/or CurrentRecord mechanism to protect against this.
mDNS_Deregister_internal(mDNS * const m,AuthRecord * const rr,mDNS_Dereg_type drt)2719*4b22b933Srs200217 mDNSlocal mStatus mDNS_Deregister_internal(mDNS *const m, AuthRecord *const rr, mDNS_Dereg_type drt)
2720*4b22b933Srs200217 {
2721*4b22b933Srs200217 AuthRecord *r2;
2722*4b22b933Srs200217 mDNSu8 RecordType = rr->resrec.RecordType;
2723*4b22b933Srs200217 AuthRecord **p = &m->ResourceRecords; // Find this record in our list of active records
2724*4b22b933Srs200217
2725*4b22b933Srs200217 #ifndef UNICAST_DISABLED
2726*4b22b933Srs200217 if (!(rr->resrec.InterfaceID == mDNSInterface_LocalOnly || rr->ForceMCast || IsLocalDomain(rr->resrec.name)))
2727*4b22b933Srs200217 return uDNS_DeregisterRecord(m, rr);
2728*4b22b933Srs200217 #endif
2729*4b22b933Srs200217
2730*4b22b933Srs200217 while (*p && *p != rr) p=&(*p)->next;
2731*4b22b933Srs200217
2732*4b22b933Srs200217 if (*p)
2733*4b22b933Srs200217 {
2734*4b22b933Srs200217 // We found our record on the main list. See if there are any duplicates that need special handling.
2735*4b22b933Srs200217 if (drt == mDNS_Dereg_conflict) // If this was a conflict, see that all duplicates get the same treatment
2736*4b22b933Srs200217 {
2737*4b22b933Srs200217 // Scan for duplicates of rr, and mark them for deregistration at the end of this routine, after we've finished
2738*4b22b933Srs200217 // deregistering rr. We need to do this scan *before* we give the client the chance to free and reuse the rr memory.
2739*4b22b933Srs200217 for (r2 = m->DuplicateRecords; r2; r2=r2->next) if (RecordIsLocalDuplicate(r2, rr)) r2->ProbeCount = 0xFF;
2740*4b22b933Srs200217 }
2741*4b22b933Srs200217 else
2742*4b22b933Srs200217 {
2743*4b22b933Srs200217 // Before we delete the record (and potentially send a goodbye packet)
2744*4b22b933Srs200217 // first see if we have a record on the duplicate list ready to take over from it.
2745*4b22b933Srs200217 AuthRecord **d = &m->DuplicateRecords;
2746*4b22b933Srs200217 while (*d && !RecordIsLocalDuplicate(*d, rr)) d=&(*d)->next;
2747*4b22b933Srs200217 if (*d)
2748*4b22b933Srs200217 {
2749*4b22b933Srs200217 AuthRecord *dup = *d;
2750*4b22b933Srs200217 debugf("Duplicate record %p taking over from %p %##s (%s)",
2751*4b22b933Srs200217 dup, rr, rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype));
2752*4b22b933Srs200217 *d = dup->next; // Cut replacement record from DuplicateRecords list
2753*4b22b933Srs200217 dup->next = rr->next; // And then...
2754*4b22b933Srs200217 rr->next = dup; // ... splice it in right after the record we're about to delete
2755*4b22b933Srs200217 dup->resrec.RecordType = rr->resrec.RecordType;
2756*4b22b933Srs200217 dup->ProbeCount = rr->ProbeCount;
2757*4b22b933Srs200217 dup->AnnounceCount = rr->AnnounceCount;
2758*4b22b933Srs200217 dup->RequireGoodbye = rr->RequireGoodbye;
2759*4b22b933Srs200217 dup->ImmedAnswer = rr->ImmedAnswer;
2760*4b22b933Srs200217 dup->ImmedUnicast = rr->ImmedUnicast;
2761*4b22b933Srs200217 dup->ImmedAdditional = rr->ImmedAdditional;
2762*4b22b933Srs200217 dup->v4Requester = rr->v4Requester;
2763*4b22b933Srs200217 dup->v6Requester = rr->v6Requester;
2764*4b22b933Srs200217 dup->ThisAPInterval = rr->ThisAPInterval;
2765*4b22b933Srs200217 dup->AnnounceUntil = rr->AnnounceUntil;
2766*4b22b933Srs200217 dup->LastAPTime = rr->LastAPTime;
2767*4b22b933Srs200217 dup->LastMCTime = rr->LastMCTime;
2768*4b22b933Srs200217 dup->LastMCInterface = rr->LastMCInterface;
2769*4b22b933Srs200217 rr->RequireGoodbye = mDNSfalse;
2770*4b22b933Srs200217 }
2771*4b22b933Srs200217 }
2772*4b22b933Srs200217 }
2773*4b22b933Srs200217 else
2774*4b22b933Srs200217 {
2775*4b22b933Srs200217 // We didn't find our record on the main list; try the DuplicateRecords list instead.
2776*4b22b933Srs200217 p = &m->DuplicateRecords;
2777*4b22b933Srs200217 while (*p && *p != rr) p=&(*p)->next;
2778*4b22b933Srs200217 // If we found our record on the duplicate list, then make sure we don't send a goodbye for it
2779*4b22b933Srs200217 if (*p) rr->RequireGoodbye = mDNSfalse;
2780*4b22b933Srs200217 if (*p) debugf("DNS_Deregister_internal: Deleting DuplicateRecord %p %##s (%s)",
2781*4b22b933Srs200217 rr, rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype));
2782*4b22b933Srs200217 }
2783*4b22b933Srs200217
2784*4b22b933Srs200217 if (!*p)
2785*4b22b933Srs200217 {
2786*4b22b933Srs200217 // No need to log an error message if we already know this is a potentially repeated deregistration
2787*4b22b933Srs200217 if (drt != mDNS_Dereg_repeat)
2788*4b22b933Srs200217 LogMsg("mDNS_Deregister_internal: Record %p %##s (%s) not found in list",
2789*4b22b933Srs200217 rr, rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype));
2790*4b22b933Srs200217 return(mStatus_BadReferenceErr);
2791*4b22b933Srs200217 }
2792*4b22b933Srs200217
2793*4b22b933Srs200217 // If this is a shared record and we've announced it at least once,
2794*4b22b933Srs200217 // we need to retract that announcement before we delete the record
2795*4b22b933Srs200217 if (RecordType == kDNSRecordTypeShared && rr->RequireGoodbye)
2796*4b22b933Srs200217 {
2797*4b22b933Srs200217 verbosedebugf("mDNS_Deregister_internal: Sending deregister for %##s (%s)",
2798*4b22b933Srs200217 rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype));
2799*4b22b933Srs200217 rr->resrec.RecordType = kDNSRecordTypeDeregistering;
2800*4b22b933Srs200217 rr->resrec.rroriginalttl = 0;
2801*4b22b933Srs200217 rr->ImmedAnswer = mDNSInterfaceMark;
2802*4b22b933Srs200217 if (m->NextScheduledResponse - (m->timenow + mDNSPlatformOneSecond/10) >= 0)
2803*4b22b933Srs200217 m->NextScheduledResponse = (m->timenow + mDNSPlatformOneSecond/10);
2804*4b22b933Srs200217 }
2805*4b22b933Srs200217 else
2806*4b22b933Srs200217 {
2807*4b22b933Srs200217 *p = rr->next; // Cut this record from the list
2808*4b22b933Srs200217 // If someone is about to look at this, bump the pointer forward
2809*4b22b933Srs200217 if (m->CurrentRecord == rr) m->CurrentRecord = rr->next;
2810*4b22b933Srs200217 if (m->NewLocalRecords == rr) m->NewLocalRecords = rr->next;
2811*4b22b933Srs200217 rr->next = mDNSNULL;
2812*4b22b933Srs200217
2813*4b22b933Srs200217 if (RecordType == kDNSRecordTypeUnregistered)
2814*4b22b933Srs200217 debugf("mDNS_Deregister_internal: Record %##s (%s) already marked kDNSRecordTypeUnregistered",
2815*4b22b933Srs200217 rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype));
2816*4b22b933Srs200217 else if (RecordType == kDNSRecordTypeDeregistering)
2817*4b22b933Srs200217 debugf("mDNS_Deregister_internal: Record %##s (%s) already marked kDNSRecordTypeDeregistering",
2818*4b22b933Srs200217 rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype));
2819*4b22b933Srs200217 else
2820*4b22b933Srs200217 {
2821*4b22b933Srs200217 verbosedebugf("mDNS_Deregister_internal: Deleting record for %##s (%s)",
2822*4b22b933Srs200217 rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype));
2823*4b22b933Srs200217 rr->resrec.RecordType = kDNSRecordTypeUnregistered;
2824*4b22b933Srs200217 }
2825*4b22b933Srs200217
2826*4b22b933Srs200217 if ((drt == mDNS_Dereg_conflict || drt == mDNS_Dereg_repeat) && RecordType == kDNSRecordTypeShared)
2827*4b22b933Srs200217 debugf("mDNS_Deregister_internal: Cannot have a conflict on a shared record! %##s (%s)",
2828*4b22b933Srs200217 rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype));
2829*4b22b933Srs200217
2830*4b22b933Srs200217 // If we have an update queued up which never executed, give the client a chance to free that memory
2831*4b22b933Srs200217 if (rr->NewRData) CompleteRDataUpdate(m, rr); // Update our rdata, clear the NewRData pointer, and return memory to the client
2832*4b22b933Srs200217
2833*4b22b933Srs200217 if (rr->LocalAnswer) AnswerLocalQuestions(m, rr, mDNSfalse);
2834*4b22b933Srs200217
2835*4b22b933Srs200217 // CAUTION: MUST NOT do anything more with rr after calling rr->Callback(), because the client's callback function
2836*4b22b933Srs200217 // is allowed to do anything, including starting/stopping queries, registering/deregistering records, etc.
2837*4b22b933Srs200217 // In this case the likely client action to the mStatus_MemFree message is to free the memory,
2838*4b22b933Srs200217 // so any attempt to touch rr after this is likely to lead to a crash.
2839*4b22b933Srs200217 m->mDNS_reentrancy++; // Increment to allow client to legally make mDNS API calls from the callback
2840*4b22b933Srs200217 if (drt != mDNS_Dereg_conflict)
2841*4b22b933Srs200217 {
2842*4b22b933Srs200217 if (rr->RecordCallback) rr->RecordCallback(m, rr, mStatus_MemFree); // MUST NOT touch rr after this
2843*4b22b933Srs200217 }
2844*4b22b933Srs200217 else
2845*4b22b933Srs200217 {
2846*4b22b933Srs200217 RecordProbeFailure(m, rr);
2847*4b22b933Srs200217 if (rr->RecordCallback) rr->RecordCallback(m, rr, mStatus_NameConflict); // MUST NOT touch rr after this
2848*4b22b933Srs200217 // Now that we've finished deregistering rr, check our DuplicateRecords list for any that we marked previously.
2849*4b22b933Srs200217 // Note that with all the client callbacks going on, by the time we get here all the
2850*4b22b933Srs200217 // records we marked may have been explicitly deregistered by the client anyway.
2851*4b22b933Srs200217 r2 = m->DuplicateRecords;
2852*4b22b933Srs200217 while (r2)
2853*4b22b933Srs200217 {
2854*4b22b933Srs200217 if (r2->ProbeCount != 0xFF) r2 = r2->next;
2855*4b22b933Srs200217 else { mDNS_Deregister_internal(m, r2, mDNS_Dereg_conflict); r2 = m->DuplicateRecords; }
2856*4b22b933Srs200217 }
2857*4b22b933Srs200217 }
2858*4b22b933Srs200217 m->mDNS_reentrancy--; // Decrement to block mDNS API calls again
2859*4b22b933Srs200217 }
2860*4b22b933Srs200217 return(mStatus_NoError);
2861*4b22b933Srs200217 }
2862*4b22b933Srs200217
2863*4b22b933Srs200217 // ***************************************************************************
2864*4b22b933Srs200217 #if COMPILER_LIKES_PRAGMA_MARK
2865*4b22b933Srs200217 #pragma mark -
2866*4b22b933Srs200217 #pragma mark -
2867*4b22b933Srs200217 #pragma mark - Packet Sending Functions
2868*4b22b933Srs200217 #endif
2869*4b22b933Srs200217
AddRecordToResponseList(AuthRecord *** nrpp,AuthRecord * rr,AuthRecord * add)2870*4b22b933Srs200217 mDNSlocal void AddRecordToResponseList(AuthRecord ***nrpp, AuthRecord *rr, AuthRecord *add)
2871*4b22b933Srs200217 {
2872*4b22b933Srs200217 if (rr->NextResponse == mDNSNULL && *nrpp != &rr->NextResponse)
2873*4b22b933Srs200217 {
2874*4b22b933Srs200217 **nrpp = rr;
2875*4b22b933Srs200217 // NR_AdditionalTo must point to a record with NR_AnswerTo set (and not NR_AdditionalTo)
2876*4b22b933Srs200217 // If 'add' does not meet this requirement, then follow its NR_AdditionalTo pointer to a record that does
2877*4b22b933Srs200217 // The referenced record will definitely be acceptable (by recursive application of this rule)
2878*4b22b933Srs200217 if (add && add->NR_AdditionalTo) add = add->NR_AdditionalTo;
2879*4b22b933Srs200217 rr->NR_AdditionalTo = add;
2880*4b22b933Srs200217 *nrpp = &rr->NextResponse;
2881*4b22b933Srs200217 }
2882*4b22b933Srs200217 debugf("AddRecordToResponseList: %##s (%s) already in list", rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype));
2883*4b22b933Srs200217 }
2884*4b22b933Srs200217
AddAdditionalsToResponseList(mDNS * const m,AuthRecord * ResponseRecords,AuthRecord *** nrpp,const mDNSInterfaceID InterfaceID)2885*4b22b933Srs200217 mDNSlocal void AddAdditionalsToResponseList(mDNS *const m, AuthRecord *ResponseRecords, AuthRecord ***nrpp, const mDNSInterfaceID InterfaceID)
2886*4b22b933Srs200217 {
2887*4b22b933Srs200217 AuthRecord *rr, *rr2;
2888*4b22b933Srs200217 for (rr=ResponseRecords; rr; rr=rr->NextResponse) // For each record we plan to put
2889*4b22b933Srs200217 {
2890*4b22b933Srs200217 // (Note: This is an "if", not a "while". If we add a record, we'll find it again
2891*4b22b933Srs200217 // later in the "for" loop, and we will follow further "additional" links then.)
2892*4b22b933Srs200217 if (rr->Additional1 && ResourceRecordIsValidInterfaceAnswer(rr->Additional1, InterfaceID))
2893*4b22b933Srs200217 AddRecordToResponseList(nrpp, rr->Additional1, rr);
2894*4b22b933Srs200217
2895*4b22b933Srs200217 if (rr->Additional2 && ResourceRecordIsValidInterfaceAnswer(rr->Additional2, InterfaceID))
2896*4b22b933Srs200217 AddRecordToResponseList(nrpp, rr->Additional2, rr);
2897*4b22b933Srs200217
2898*4b22b933Srs200217 // For SRV records, automatically add the Address record(s) for the target host
2899*4b22b933Srs200217 if (rr->resrec.rrtype == kDNSType_SRV)
2900*4b22b933Srs200217 for (rr2=m->ResourceRecords; rr2; rr2=rr2->next) // Scan list of resource records
2901*4b22b933Srs200217 if (RRTypeIsAddressType(rr2->resrec.rrtype) && // For all address records (A/AAAA) ...
2902*4b22b933Srs200217 ResourceRecordIsValidInterfaceAnswer(rr2, InterfaceID) && // ... which are valid for answer ...
2903*4b22b933Srs200217 rr->resrec.rdatahash == rr2->resrec.namehash && // ... whose name is the name of the SRV target
2904*4b22b933Srs200217 SameDomainName(&rr->resrec.rdata->u.srv.target, rr2->resrec.name))
2905*4b22b933Srs200217 AddRecordToResponseList(nrpp, rr2, rr);
2906*4b22b933Srs200217 }
2907*4b22b933Srs200217 }
2908*4b22b933Srs200217
SendDelayedUnicastResponse(mDNS * const m,const mDNSAddr * const dest,const mDNSInterfaceID InterfaceID)2909*4b22b933Srs200217 mDNSlocal void SendDelayedUnicastResponse(mDNS *const m, const mDNSAddr *const dest, const mDNSInterfaceID InterfaceID)
2910*4b22b933Srs200217 {
2911*4b22b933Srs200217 AuthRecord *rr;
2912*4b22b933Srs200217 AuthRecord *ResponseRecords = mDNSNULL;
2913*4b22b933Srs200217 AuthRecord **nrp = &ResponseRecords;
2914*4b22b933Srs200217
2915*4b22b933Srs200217 // Make a list of all our records that need to be unicast to this destination
2916*4b22b933Srs200217 for (rr = m->ResourceRecords; rr; rr=rr->next)
2917*4b22b933Srs200217 {
2918*4b22b933Srs200217 // If we find we can no longer unicast this answer, clear ImmedUnicast
2919*4b22b933Srs200217 if (rr->ImmedAnswer == mDNSInterfaceMark ||
2920*4b22b933Srs200217 mDNSSameIPv4Address(rr->v4Requester, onesIPv4Addr) ||
2921*4b22b933Srs200217 mDNSSameIPv6Address(rr->v6Requester, onesIPv6Addr) )
2922*4b22b933Srs200217 rr->ImmedUnicast = mDNSfalse;
2923*4b22b933Srs200217
2924*4b22b933Srs200217 if (rr->ImmedUnicast && rr->ImmedAnswer == InterfaceID)
2925*4b22b933Srs200217 if ((dest->type == mDNSAddrType_IPv4 && mDNSSameIPv4Address(rr->v4Requester, dest->ip.v4)) ||
2926*4b22b933Srs200217 (dest->type == mDNSAddrType_IPv6 && mDNSSameIPv6Address(rr->v6Requester, dest->ip.v6)))
2927*4b22b933Srs200217 {
2928*4b22b933Srs200217 rr->ImmedAnswer = mDNSNULL; // Clear the state fields
2929*4b22b933Srs200217 rr->ImmedUnicast = mDNSfalse;
2930*4b22b933Srs200217 rr->v4Requester = zerov4Addr;
2931*4b22b933Srs200217 rr->v6Requester = zerov6Addr;
2932*4b22b933Srs200217 if (rr->NextResponse == mDNSNULL && nrp != &rr->NextResponse) // rr->NR_AnswerTo
2933*4b22b933Srs200217 { rr->NR_AnswerTo = (mDNSu8*)~0; *nrp = rr; nrp = &rr->NextResponse; }
2934*4b22b933Srs200217 }
2935*4b22b933Srs200217 }
2936*4b22b933Srs200217
2937*4b22b933Srs200217 AddAdditionalsToResponseList(m, ResponseRecords, &nrp, InterfaceID);
2938*4b22b933Srs200217
2939*4b22b933Srs200217 while (ResponseRecords)
2940*4b22b933Srs200217 {
2941*4b22b933Srs200217 mDNSu8 *responseptr = m->omsg.data;
2942*4b22b933Srs200217 mDNSu8 *newptr;
2943*4b22b933Srs200217 InitializeDNSMessage(&m->omsg.h, zeroID, ResponseFlags);
2944*4b22b933Srs200217
2945*4b22b933Srs200217 // Put answers in the packet
2946*4b22b933Srs200217 while (ResponseRecords && ResponseRecords->NR_AnswerTo)
2947*4b22b933Srs200217 {
2948*4b22b933Srs200217 rr = ResponseRecords;
2949*4b22b933Srs200217 if (rr->resrec.RecordType & kDNSRecordTypeUniqueMask)
2950*4b22b933Srs200217 rr->resrec.rrclass |= kDNSClass_UniqueRRSet; // Temporarily set the cache flush bit so PutResourceRecord will set it
2951*4b22b933Srs200217 newptr = PutResourceRecord(&m->omsg, responseptr, &m->omsg.h.numAnswers, &rr->resrec);
2952*4b22b933Srs200217 rr->resrec.rrclass &= ~kDNSClass_UniqueRRSet; // Make sure to clear cache flush bit back to normal state
2953*4b22b933Srs200217 if (!newptr && m->omsg.h.numAnswers) break; // If packet full, send it now
2954*4b22b933Srs200217 if (newptr) responseptr = newptr;
2955*4b22b933Srs200217 ResponseRecords = rr->NextResponse;
2956*4b22b933Srs200217 rr->NextResponse = mDNSNULL;
2957*4b22b933Srs200217 rr->NR_AnswerTo = mDNSNULL;
2958*4b22b933Srs200217 rr->NR_AdditionalTo = mDNSNULL;
2959*4b22b933Srs200217 rr->RequireGoodbye = mDNStrue;
2960*4b22b933Srs200217 }
2961*4b22b933Srs200217
2962*4b22b933Srs200217 // Add additionals, if there's space
2963*4b22b933Srs200217 while (ResponseRecords && !ResponseRecords->NR_AnswerTo)
2964*4b22b933Srs200217 {
2965*4b22b933Srs200217 rr = ResponseRecords;
2966*4b22b933Srs200217 if (rr->resrec.RecordType & kDNSRecordTypeUniqueMask)
2967*4b22b933Srs200217 rr->resrec.rrclass |= kDNSClass_UniqueRRSet; // Temporarily set the cache flush bit so PutResourceRecord will set it
2968*4b22b933Srs200217 newptr = PutResourceRecord(&m->omsg, responseptr, &m->omsg.h.numAdditionals, &rr->resrec);
2969*4b22b933Srs200217 rr->resrec.rrclass &= ~kDNSClass_UniqueRRSet; // Make sure to clear cache flush bit back to normal state
2970*4b22b933Srs200217
2971*4b22b933Srs200217 if (newptr) responseptr = newptr;
2972*4b22b933Srs200217 if (newptr && m->omsg.h.numAnswers) rr->RequireGoodbye = mDNStrue;
2973*4b22b933Srs200217 else if (rr->resrec.RecordType & kDNSRecordTypeUniqueMask) rr->ImmedAnswer = mDNSInterfaceMark;
2974*4b22b933Srs200217 ResponseRecords = rr->NextResponse;
2975*4b22b933Srs200217 rr->NextResponse = mDNSNULL;
2976*4b22b933Srs200217 rr->NR_AnswerTo = mDNSNULL;
2977*4b22b933Srs200217 rr->NR_AdditionalTo = mDNSNULL;
2978*4b22b933Srs200217 }
2979*4b22b933Srs200217
2980*4b22b933Srs200217 if (m->omsg.h.numAnswers) mDNSSendDNSMessage(m, &m->omsg, responseptr, mDNSInterface_Any, dest, MulticastDNSPort, -1, mDNSNULL);
2981*4b22b933Srs200217 }
2982*4b22b933Srs200217 }
2983*4b22b933Srs200217
CompleteDeregistration(mDNS * const m,AuthRecord * rr)2984*4b22b933Srs200217 mDNSlocal void CompleteDeregistration(mDNS *const m, AuthRecord *rr)
2985*4b22b933Srs200217 {
2986*4b22b933Srs200217 // Clearing rr->RequireGoodbye signals mDNS_Deregister_internal()
2987*4b22b933Srs200217 // that it should go ahead and immediately dispose of this registration
2988*4b22b933Srs200217 rr->resrec.RecordType = kDNSRecordTypeShared;
2989*4b22b933Srs200217 rr->RequireGoodbye = mDNSfalse;
2990*4b22b933Srs200217 mDNS_Deregister_internal(m, rr, mDNS_Dereg_normal); // Don't touch rr after this
2991*4b22b933Srs200217 }
2992*4b22b933Srs200217
2993*4b22b933Srs200217 // NOTE: DiscardDeregistrations calls mDNS_Deregister_internal which can call a user callback, which may change
2994*4b22b933Srs200217 // the record list and/or question list.
2995*4b22b933Srs200217 // Any code walking either list must use the CurrentQuestion and/or CurrentRecord mechanism to protect against this.
DiscardDeregistrations(mDNS * const m)2996*4b22b933Srs200217 mDNSlocal void DiscardDeregistrations(mDNS *const m)
2997*4b22b933Srs200217 {
2998*4b22b933Srs200217 if (m->CurrentRecord) LogMsg("DiscardDeregistrations ERROR m->CurrentRecord already set");
2999*4b22b933Srs200217 m->CurrentRecord = m->ResourceRecords;
3000*4b22b933Srs200217
3001*4b22b933Srs200217 while (m->CurrentRecord)
3002*4b22b933Srs200217 {
3003*4b22b933Srs200217 AuthRecord *rr = m->CurrentRecord;
3004*4b22b933Srs200217 if (rr->resrec.RecordType == kDNSRecordTypeDeregistering)
3005*4b22b933Srs200217 CompleteDeregistration(m, rr); // Don't touch rr after this
3006*4b22b933Srs200217 else
3007*4b22b933Srs200217 m->CurrentRecord = rr->next;
3008*4b22b933Srs200217 }
3009*4b22b933Srs200217 }
3010*4b22b933Srs200217
GrantUpdateCredit(AuthRecord * rr)3011*4b22b933Srs200217 mDNSlocal void GrantUpdateCredit(AuthRecord *rr)
3012*4b22b933Srs200217 {
3013*4b22b933Srs200217 if (++rr->UpdateCredits >= kMaxUpdateCredits) rr->NextUpdateCredit = 0;
3014*4b22b933Srs200217 else rr->NextUpdateCredit = NonZeroTime(rr->NextUpdateCredit + kUpdateCreditRefreshInterval);
3015*4b22b933Srs200217 }
3016*4b22b933Srs200217
3017*4b22b933Srs200217 // Note about acceleration of announcements to facilitate automatic coalescing of
3018*4b22b933Srs200217 // multiple independent threads of announcements into a single synchronized thread:
3019*4b22b933Srs200217 // The announcements in the packet may be at different stages of maturity;
3020*4b22b933Srs200217 // One-second interval, two-second interval, four-second interval, and so on.
3021*4b22b933Srs200217 // After we've put in all the announcements that are due, we then consider
3022*4b22b933Srs200217 // whether there are other nearly-due announcements that are worth accelerating.
3023*4b22b933Srs200217 // To be eligible for acceleration, a record MUST NOT be older (further along
3024*4b22b933Srs200217 // its timeline) than the most mature record we've already put in the packet.
3025*4b22b933Srs200217 // In other words, younger records can have their timelines accelerated to catch up
3026*4b22b933Srs200217 // with their elder bretheren; this narrows the age gap and helps them eventually get in sync.
3027*4b22b933Srs200217 // Older records cannot have their timelines accelerated; this would just widen
3028*4b22b933Srs200217 // the gap between them and their younger bretheren and get them even more out of sync.
3029*4b22b933Srs200217
3030*4b22b933Srs200217 // NOTE: SendResponses calls mDNS_Deregister_internal which can call a user callback, which may change
3031*4b22b933Srs200217 // the record list and/or question list.
3032*4b22b933Srs200217 // Any code walking either list must use the CurrentQuestion and/or CurrentRecord mechanism to protect against this.
SendResponses(mDNS * const m)3033*4b22b933Srs200217 mDNSlocal void SendResponses(mDNS *const m)
3034*4b22b933Srs200217 {
3035*4b22b933Srs200217 int pktcount = 0;
3036*4b22b933Srs200217 AuthRecord *rr, *r2;
3037*4b22b933Srs200217 mDNSs32 maxExistingAnnounceInterval = 0;
3038*4b22b933Srs200217 const NetworkInterfaceInfo *intf = GetFirstActiveInterface(m->HostInterfaces);
3039*4b22b933Srs200217
3040*4b22b933Srs200217 m->NextScheduledResponse = m->timenow + 0x78000000;
3041*4b22b933Srs200217
3042*4b22b933Srs200217 for (rr = m->ResourceRecords; rr; rr=rr->next)
3043*4b22b933Srs200217 if (rr->ImmedUnicast)
3044*4b22b933Srs200217 {
3045*4b22b933Srs200217 mDNSAddr v4 = { mDNSAddrType_IPv4, {{{0}}} };
3046*4b22b933Srs200217 mDNSAddr v6 = { mDNSAddrType_IPv6, {{{0}}} };
3047*4b22b933Srs200217 v4.ip.v4 = rr->v4Requester;
3048*4b22b933Srs200217 v6.ip.v6 = rr->v6Requester;
3049*4b22b933Srs200217 if (!mDNSIPv4AddressIsZero(rr->v4Requester)) SendDelayedUnicastResponse(m, &v4, rr->ImmedAnswer);
3050*4b22b933Srs200217 if (!mDNSIPv6AddressIsZero(rr->v6Requester)) SendDelayedUnicastResponse(m, &v6, rr->ImmedAnswer);
3051*4b22b933Srs200217 if (rr->ImmedUnicast)
3052*4b22b933Srs200217 {
3053*4b22b933Srs200217 LogMsg("SendResponses: ERROR: rr->ImmedUnicast still set: %s", ARDisplayString(m, rr));
3054*4b22b933Srs200217 rr->ImmedUnicast = mDNSfalse;
3055*4b22b933Srs200217 }
3056*4b22b933Srs200217 }
3057*4b22b933Srs200217
3058*4b22b933Srs200217 // ***
3059*4b22b933Srs200217 // *** 1. Setup: Set the SendRNow and ImmedAnswer fields to indicate which interface(s) the records need to be sent on
3060*4b22b933Srs200217 // ***
3061*4b22b933Srs200217
3062*4b22b933Srs200217 // Run through our list of records, and decide which ones we're going to announce on all interfaces
3063*4b22b933Srs200217 for (rr = m->ResourceRecords; rr; rr=rr->next)
3064*4b22b933Srs200217 {
3065*4b22b933Srs200217 while (rr->NextUpdateCredit && m->timenow - rr->NextUpdateCredit >= 0) GrantUpdateCredit(rr);
3066*4b22b933Srs200217 if (TimeToAnnounceThisRecord(rr, m->timenow) && ResourceRecordIsValidAnswer(rr))
3067*4b22b933Srs200217 {
3068*4b22b933Srs200217 rr->ImmedAnswer = mDNSInterfaceMark; // Send on all interfaces
3069*4b22b933Srs200217 if (maxExistingAnnounceInterval < rr->ThisAPInterval)
3070*4b22b933Srs200217 maxExistingAnnounceInterval = rr->ThisAPInterval;
3071*4b22b933Srs200217 if (rr->UpdateBlocked) rr->UpdateBlocked = 0;
3072*4b22b933Srs200217 }
3073*4b22b933Srs200217 }
3074*4b22b933Srs200217
3075*4b22b933Srs200217 // Any interface-specific records we're going to send are marked as being sent on all appropriate interfaces (which is just one)
3076*4b22b933Srs200217 // Eligible records that are more than half-way to their announcement time are accelerated
3077*4b22b933Srs200217 for (rr = m->ResourceRecords; rr; rr=rr->next)
3078*4b22b933Srs200217 if ((rr->resrec.InterfaceID && rr->ImmedAnswer) ||
3079*4b22b933Srs200217 (rr->ThisAPInterval <= maxExistingAnnounceInterval &&
3080*4b22b933Srs200217 TimeToAnnounceThisRecord(rr, m->timenow + rr->ThisAPInterval/2) &&
3081*4b22b933Srs200217 ResourceRecordIsValidAnswer(rr)))
3082*4b22b933Srs200217 rr->ImmedAnswer = mDNSInterfaceMark; // Send on all interfaces
3083*4b22b933Srs200217
3084*4b22b933Srs200217 // When sending SRV records (particularly when announcing a new service) automatically add related Address record(s) as additionals
3085*4b22b933Srs200217 // NOTE: Currently all address records are interface-specific, so it's safe to set ImmedAdditional to their InterfaceID,
3086*4b22b933Srs200217 // which will be non-null. If by some chance there is an address record that's not interface-specific (should never happen)
3087*4b22b933Srs200217 // then all that means is that it won't get sent -- which would not be the end of the world.
3088*4b22b933Srs200217 for (rr = m->ResourceRecords; rr; rr=rr->next)
3089*4b22b933Srs200217 if (rr->ImmedAnswer && rr->resrec.rrtype == kDNSType_SRV)
3090*4b22b933Srs200217 for (r2=m->ResourceRecords; r2; r2=r2->next) // Scan list of resource records
3091*4b22b933Srs200217 if (RRTypeIsAddressType(r2->resrec.rrtype) && // For all address records (A/AAAA) ...
3092*4b22b933Srs200217 ResourceRecordIsValidAnswer(r2) && // ... which are valid for answer ...
3093*4b22b933Srs200217 rr->LastMCTime - r2->LastMCTime >= 0 && // ... which we have not sent recently ...
3094*4b22b933Srs200217 rr->resrec.rdatahash == r2->resrec.namehash && // ... whose name is the name of the SRV target
3095*4b22b933Srs200217 SameDomainName(&rr->resrec.rdata->u.srv.target, r2->resrec.name) &&
3096*4b22b933Srs200217 (rr->ImmedAnswer == mDNSInterfaceMark || rr->ImmedAnswer == r2->resrec.InterfaceID))
3097*4b22b933Srs200217 r2->ImmedAdditional = r2->resrec.InterfaceID; // ... then mark this address record for sending too
3098*4b22b933Srs200217
3099*4b22b933Srs200217 // If there's a record which is supposed to be unique that we're going to send, then make sure that we give
3100*4b22b933Srs200217 // the whole RRSet as an atomic unit. That means that if we have any other records with the same name/type/class
3101*4b22b933Srs200217 // then we need to mark them for sending too. Otherwise, if we set the kDNSClass_UniqueRRSet bit on a
3102*4b22b933Srs200217 // record, then other RRSet members that have not been sent recently will get flushed out of client caches.
3103*4b22b933Srs200217 // -- If a record is marked to be sent on a certain interface, make sure the whole set is marked to be sent on that interface
3104*4b22b933Srs200217 // -- If any record is marked to be sent on all interfaces, make sure the whole set is marked to be sent on all interfaces
3105*4b22b933Srs200217 for (rr = m->ResourceRecords; rr; rr=rr->next)
3106*4b22b933Srs200217 if (rr->resrec.RecordType & kDNSRecordTypeUniqueMask)
3107*4b22b933Srs200217 {
3108*4b22b933Srs200217 if (rr->ImmedAnswer) // If we're sending this as answer, see that its whole RRSet is similarly marked
3109*4b22b933Srs200217 {
3110*4b22b933Srs200217 for (r2 = m->ResourceRecords; r2; r2=r2->next)
3111*4b22b933Srs200217 if (ResourceRecordIsValidAnswer(r2))
3112*4b22b933Srs200217 if (r2->ImmedAnswer != mDNSInterfaceMark &&
3113*4b22b933Srs200217 r2->ImmedAnswer != rr->ImmedAnswer && SameResourceRecordSignature(&r2->resrec, &rr->resrec))
3114*4b22b933Srs200217 r2->ImmedAnswer = rr->ImmedAnswer;
3115*4b22b933Srs200217 }
3116*4b22b933Srs200217 else if (rr->ImmedAdditional) // If we're sending this as additional, see that its whole RRSet is similarly marked
3117*4b22b933Srs200217 {
3118*4b22b933Srs200217 for (r2 = m->ResourceRecords; r2; r2=r2->next)
3119*4b22b933Srs200217 if (ResourceRecordIsValidAnswer(r2))
3120*4b22b933Srs200217 if (r2->ImmedAdditional != rr->ImmedAdditional && SameResourceRecordSignature(&r2->resrec, &rr->resrec))
3121*4b22b933Srs200217 r2->ImmedAdditional = rr->ImmedAdditional;
3122*4b22b933Srs200217 }
3123*4b22b933Srs200217 }
3124*4b22b933Srs200217
3125*4b22b933Srs200217 // Now set SendRNow state appropriately
3126*4b22b933Srs200217 for (rr = m->ResourceRecords; rr; rr=rr->next)
3127*4b22b933Srs200217 {
3128*4b22b933Srs200217 if (rr->ImmedAnswer == mDNSInterfaceMark) // Sending this record on all appropriate interfaces
3129*4b22b933Srs200217 {
3130*4b22b933Srs200217 rr->SendRNow = !intf ? mDNSNULL : (rr->resrec.InterfaceID) ? rr->resrec.InterfaceID : intf->InterfaceID;
3131*4b22b933Srs200217 rr->ImmedAdditional = mDNSNULL; // No need to send as additional if sending as answer
3132*4b22b933Srs200217 rr->LastMCTime = m->timenow;
3133*4b22b933Srs200217 rr->LastMCInterface = rr->ImmedAnswer;
3134*4b22b933Srs200217 // If we're announcing this record, and it's at least half-way to its ordained time, then consider this announcement done
3135*4b22b933Srs200217 if (TimeToAnnounceThisRecord(rr, m->timenow + rr->ThisAPInterval/2))
3136*4b22b933Srs200217 {
3137*4b22b933Srs200217 rr->AnnounceCount--;
3138*4b22b933Srs200217 rr->ThisAPInterval *= 2;
3139*4b22b933Srs200217 rr->LastAPTime = m->timenow;
3140*4b22b933Srs200217 if (rr->LastAPTime + rr->ThisAPInterval - rr->AnnounceUntil >= 0) rr->AnnounceCount = 0;
3141*4b22b933Srs200217 debugf("Announcing %##s (%s) %d", rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype), rr->AnnounceCount);
3142*4b22b933Srs200217 }
3143*4b22b933Srs200217 }
3144*4b22b933Srs200217 else if (rr->ImmedAnswer) // Else, just respond to a single query on single interface:
3145*4b22b933Srs200217 {
3146*4b22b933Srs200217 rr->SendRNow = rr->ImmedAnswer; // Just respond on that interface
3147*4b22b933Srs200217 rr->ImmedAdditional = mDNSNULL; // No need to send as additional too
3148*4b22b933Srs200217 rr->LastMCTime = m->timenow;
3149*4b22b933Srs200217 rr->LastMCInterface = rr->ImmedAnswer;
3150*4b22b933Srs200217 }
3151*4b22b933Srs200217 SetNextAnnounceProbeTime(m, rr);
3152*4b22b933Srs200217 //if (rr->SendRNow) LogMsg("%-15.4a %s", &rr->v4Requester, ARDisplayString(m, rr));
3153*4b22b933Srs200217 }
3154*4b22b933Srs200217
3155*4b22b933Srs200217 // ***
3156*4b22b933Srs200217 // *** 2. Loop through interface list, sending records as appropriate
3157*4b22b933Srs200217 // ***
3158*4b22b933Srs200217
3159*4b22b933Srs200217 while (intf)
3160*4b22b933Srs200217 {
3161*4b22b933Srs200217 int numDereg = 0;
3162*4b22b933Srs200217 int numAnnounce = 0;
3163*4b22b933Srs200217 int numAnswer = 0;
3164*4b22b933Srs200217 mDNSu8 *responseptr = m->omsg.data;
3165*4b22b933Srs200217 mDNSu8 *newptr;
3166*4b22b933Srs200217 InitializeDNSMessage(&m->omsg.h, zeroID, ResponseFlags);
3167*4b22b933Srs200217
3168*4b22b933Srs200217 // First Pass. Look for:
3169*4b22b933Srs200217 // 1. Deregistering records that need to send their goodbye packet
3170*4b22b933Srs200217 // 2. Updated records that need to retract their old data
3171*4b22b933Srs200217 // 3. Answers and announcements we need to send
3172*4b22b933Srs200217 // In all cases, if we fail, and we've put at least one answer, we break out of the for loop so we can
3173*4b22b933Srs200217 // send this packet and then try again.
3174*4b22b933Srs200217 // If we have not put even one answer, then we don't bail out. We pretend we succeeded anyway,
3175*4b22b933Srs200217 // because otherwise we'll end up in an infinite loop trying to send a record that will never fit.
3176*4b22b933Srs200217 for (rr = m->ResourceRecords; rr; rr=rr->next)
3177*4b22b933Srs200217 if (rr->SendRNow == intf->InterfaceID)
3178*4b22b933Srs200217 {
3179*4b22b933Srs200217 if (rr->resrec.RecordType == kDNSRecordTypeDeregistering)
3180*4b22b933Srs200217 {
3181*4b22b933Srs200217 newptr = PutResourceRecordTTL(&m->omsg, responseptr, &m->omsg.h.numAnswers, &rr->resrec, 0);
3182*4b22b933Srs200217 if (!newptr && m->omsg.h.numAnswers) break;
3183*4b22b933Srs200217 numDereg++;
3184*4b22b933Srs200217 responseptr = newptr;
3185*4b22b933Srs200217 }
3186*4b22b933Srs200217 else if (rr->NewRData && !m->SleepState) // If we have new data for this record
3187*4b22b933Srs200217 {
3188*4b22b933Srs200217 RData *OldRData = rr->resrec.rdata;
3189*4b22b933Srs200217 mDNSu16 oldrdlength = rr->resrec.rdlength;
3190*4b22b933Srs200217 // See if we should send a courtesy "goodbye" for the old data before we replace it.
3191*4b22b933Srs200217 if (ResourceRecordIsValidAnswer(rr) && rr->RequireGoodbye)
3192*4b22b933Srs200217 {
3193*4b22b933Srs200217 newptr = PutResourceRecordTTL(&m->omsg, responseptr, &m->omsg.h.numAnswers, &rr->resrec, 0);
3194*4b22b933Srs200217 if (!newptr && m->omsg.h.numAnswers) break;
3195*4b22b933Srs200217 numDereg++;
3196*4b22b933Srs200217 responseptr = newptr;
3197*4b22b933Srs200217 rr->RequireGoodbye = mDNSfalse;
3198*4b22b933Srs200217 }
3199*4b22b933Srs200217 // Now try to see if we can fit the update in the same packet (not fatal if we can't)
3200*4b22b933Srs200217 SetNewRData(&rr->resrec, rr->NewRData, rr->newrdlength);
3201*4b22b933Srs200217 if (rr->resrec.RecordType & kDNSRecordTypeUniqueMask)
3202*4b22b933Srs200217 rr->resrec.rrclass |= kDNSClass_UniqueRRSet; // Temporarily set the cache flush bit so PutResourceRecord will set it
3203*4b22b933Srs200217 newptr = PutResourceRecord(&m->omsg, responseptr, &m->omsg.h.numAnswers, &rr->resrec);
3204*4b22b933Srs200217 rr->resrec.rrclass &= ~kDNSClass_UniqueRRSet; // Make sure to clear cache flush bit back to normal state
3205*4b22b933Srs200217 if (newptr) { responseptr = newptr; rr->RequireGoodbye = mDNStrue; }
3206*4b22b933Srs200217 SetNewRData(&rr->resrec, OldRData, oldrdlength);
3207*4b22b933Srs200217 }
3208*4b22b933Srs200217 else
3209*4b22b933Srs200217 {
3210*4b22b933Srs200217 if (rr->resrec.RecordType & kDNSRecordTypeUniqueMask)
3211*4b22b933Srs200217 rr->resrec.rrclass |= kDNSClass_UniqueRRSet; // Temporarily set the cache flush bit so PutResourceRecord will set it
3212*4b22b933Srs200217 newptr = PutResourceRecordTTL(&m->omsg, responseptr, &m->omsg.h.numAnswers, &rr->resrec, m->SleepState ? 0 : rr->resrec.rroriginalttl);
3213*4b22b933Srs200217 rr->resrec.rrclass &= ~kDNSClass_UniqueRRSet; // Make sure to clear cache flush bit back to normal state
3214*4b22b933Srs200217 if (!newptr && m->omsg.h.numAnswers) break;
3215*4b22b933Srs200217 rr->RequireGoodbye = (mDNSu8) (!m->SleepState);
3216*4b22b933Srs200217 if (rr->LastAPTime == m->timenow) numAnnounce++; else numAnswer++;
3217*4b22b933Srs200217 responseptr = newptr;
3218*4b22b933Srs200217 }
3219*4b22b933Srs200217 // If sending on all interfaces, go to next interface; else we're finished now
3220*4b22b933Srs200217 if (rr->ImmedAnswer == mDNSInterfaceMark && rr->resrec.InterfaceID == mDNSInterface_Any)
3221*4b22b933Srs200217 rr->SendRNow = GetNextActiveInterfaceID(intf);
3222*4b22b933Srs200217 else
3223*4b22b933Srs200217 rr->SendRNow = mDNSNULL;
3224*4b22b933Srs200217 }
3225*4b22b933Srs200217
3226*4b22b933Srs200217 // Second Pass. Add additional records, if there's space.
3227*4b22b933Srs200217 newptr = responseptr;
3228*4b22b933Srs200217 for (rr = m->ResourceRecords; rr; rr=rr->next)
3229*4b22b933Srs200217 if (rr->ImmedAdditional == intf->InterfaceID)
3230*4b22b933Srs200217 if (ResourceRecordIsValidAnswer(rr))
3231*4b22b933Srs200217 {
3232*4b22b933Srs200217 // If we have at least one answer already in the packet, then plan to add additionals too
3233*4b22b933Srs200217 mDNSBool SendAdditional = (m->omsg.h.numAnswers > 0);
3234*4b22b933Srs200217
3235*4b22b933Srs200217 // If we're not planning to send any additionals, but this record is a unique one, then
3236*4b22b933Srs200217 // make sure we haven't already sent any other members of its RRSet -- if we have, then they
3237*4b22b933Srs200217 // will have had the cache flush bit set, so now we need to finish the job and send the rest.
3238*4b22b933Srs200217 if (!SendAdditional && (rr->resrec.RecordType & kDNSRecordTypeUniqueMask))
3239*4b22b933Srs200217 {
3240*4b22b933Srs200217 const AuthRecord *a;
3241*4b22b933Srs200217 for (a = m->ResourceRecords; a; a=a->next)
3242*4b22b933Srs200217 if (a->LastMCTime == m->timenow &&
3243*4b22b933Srs200217 a->LastMCInterface == intf->InterfaceID &&
3244*4b22b933Srs200217 SameResourceRecordSignature(&a->resrec, &rr->resrec)) { SendAdditional = mDNStrue; break; }
3245*4b22b933Srs200217 }
3246*4b22b933Srs200217 if (!SendAdditional) // If we don't want to send this after all,
3247*4b22b933Srs200217 rr->ImmedAdditional = mDNSNULL; // then cancel its ImmedAdditional field
3248*4b22b933Srs200217 else if (newptr) // Else, try to add it if we can
3249*4b22b933Srs200217 {
3250*4b22b933Srs200217 if (rr->resrec.RecordType & kDNSRecordTypeUniqueMask)
3251*4b22b933Srs200217 rr->resrec.rrclass |= kDNSClass_UniqueRRSet; // Temporarily set the cache flush bit so PutResourceRecord will set it
3252*4b22b933Srs200217 newptr = PutResourceRecord(&m->omsg, newptr, &m->omsg.h.numAdditionals, &rr->resrec);
3253*4b22b933Srs200217 rr->resrec.rrclass &= ~kDNSClass_UniqueRRSet; // Make sure to clear cache flush bit back to normal state
3254*4b22b933Srs200217 if (newptr)
3255*4b22b933Srs200217 {
3256*4b22b933Srs200217 responseptr = newptr;
3257*4b22b933Srs200217 rr->ImmedAdditional = mDNSNULL;
3258*4b22b933Srs200217 rr->RequireGoodbye = mDNStrue;
3259*4b22b933Srs200217 // If we successfully put this additional record in the packet, we record LastMCTime & LastMCInterface.
3260*4b22b933Srs200217 // This matters particularly in the case where we have more than one IPv6 (or IPv4) address, because otherwise,
3261*4b22b933Srs200217 // when we see our own multicast with the cache flush bit set, if we haven't set LastMCTime, then we'll get
3262*4b22b933Srs200217 // all concerned and re-announce our record again to make sure it doesn't get flushed from peer caches.
3263*4b22b933Srs200217 rr->LastMCTime = m->timenow;
3264*4b22b933Srs200217 rr->LastMCInterface = intf->InterfaceID;
3265*4b22b933Srs200217 }
3266*4b22b933Srs200217 }
3267*4b22b933Srs200217 }
3268*4b22b933Srs200217
3269*4b22b933Srs200217 if (m->omsg.h.numAnswers > 0 || m->omsg.h.numAdditionals)
3270*4b22b933Srs200217 {
3271*4b22b933Srs200217 debugf("SendResponses: Sending %d Deregistration%s, %d Announcement%s, %d Answer%s, %d Additional%s on %p",
3272*4b22b933Srs200217 numDereg, numDereg == 1 ? "" : "s",
3273*4b22b933Srs200217 numAnnounce, numAnnounce == 1 ? "" : "s",
3274*4b22b933Srs200217 numAnswer, numAnswer == 1 ? "" : "s",
3275*4b22b933Srs200217 m->omsg.h.numAdditionals, m->omsg.h.numAdditionals == 1 ? "" : "s", intf->InterfaceID);
3276*4b22b933Srs200217 if (intf->IPv4Available) mDNSSendDNSMessage(m, &m->omsg, responseptr, intf->InterfaceID, &AllDNSLinkGroup_v4, MulticastDNSPort, -1, mDNSNULL);
3277*4b22b933Srs200217 if (intf->IPv6Available) mDNSSendDNSMessage(m, &m->omsg, responseptr, intf->InterfaceID, &AllDNSLinkGroup_v6, MulticastDNSPort, -1, mDNSNULL);
3278*4b22b933Srs200217 if (!m->SuppressSending) m->SuppressSending = NonZeroTime(m->timenow + (mDNSPlatformOneSecond+9)/10);
3279*4b22b933Srs200217 if (++pktcount >= 1000) { LogMsg("SendResponses exceeded loop limit %d: giving up", pktcount); break; }
3280*4b22b933Srs200217 // There might be more things to send on this interface, so go around one more time and try again.
3281*4b22b933Srs200217 }
3282*4b22b933Srs200217 else // Nothing more to send on this interface; go to next
3283*4b22b933Srs200217 {
3284*4b22b933Srs200217 const NetworkInterfaceInfo *next = GetFirstActiveInterface(intf->next);
3285*4b22b933Srs200217 #if MDNS_DEBUGMSGS && 0
3286*4b22b933Srs200217 const char *const msg = next ? "SendResponses: Nothing more on %p; moving to %p" : "SendResponses: Nothing more on %p";
3287*4b22b933Srs200217 debugf(msg, intf, next);
3288*4b22b933Srs200217 #endif
3289*4b22b933Srs200217 intf = next;
3290*4b22b933Srs200217 }
3291*4b22b933Srs200217 }
3292*4b22b933Srs200217
3293*4b22b933Srs200217 // ***
3294*4b22b933Srs200217 // *** 3. Cleanup: Now that everything is sent, call client callback functions, and reset state variables
3295*4b22b933Srs200217 // ***
3296*4b22b933Srs200217
3297*4b22b933Srs200217 if (m->CurrentRecord) LogMsg("SendResponses: ERROR m->CurrentRecord already set");
3298*4b22b933Srs200217 m->CurrentRecord = m->ResourceRecords;
3299*4b22b933Srs200217 while (m->CurrentRecord)
3300*4b22b933Srs200217 {
3301*4b22b933Srs200217 rr = m->CurrentRecord;
3302*4b22b933Srs200217 m->CurrentRecord = rr->next;
3303*4b22b933Srs200217
3304*4b22b933Srs200217 if (rr->SendRNow)
3305*4b22b933Srs200217 {
3306*4b22b933Srs200217 if (rr->resrec.InterfaceID != mDNSInterface_LocalOnly)
3307*4b22b933Srs200217 LogMsg("SendResponses: No active interface to send: %s", ARDisplayString(m, rr));
3308*4b22b933Srs200217 rr->SendRNow = mDNSNULL;
3309*4b22b933Srs200217 }
3310*4b22b933Srs200217
3311*4b22b933Srs200217 if (rr->ImmedAnswer)
3312*4b22b933Srs200217 {
3313*4b22b933Srs200217 if (rr->NewRData) CompleteRDataUpdate(m,rr); // Update our rdata, clear the NewRData pointer, and return memory to the client
3314*4b22b933Srs200217
3315*4b22b933Srs200217 if (rr->resrec.RecordType == kDNSRecordTypeDeregistering)
3316*4b22b933Srs200217 CompleteDeregistration(m, rr); // Don't touch rr after this
3317*4b22b933Srs200217 else
3318*4b22b933Srs200217 {
3319*4b22b933Srs200217 rr->ImmedAnswer = mDNSNULL;
3320*4b22b933Srs200217 rr->ImmedUnicast = mDNSfalse;
3321*4b22b933Srs200217 rr->v4Requester = zerov4Addr;
3322*4b22b933Srs200217 rr->v6Requester = zerov6Addr;
3323*4b22b933Srs200217 }
3324*4b22b933Srs200217 }
3325*4b22b933Srs200217 }
3326*4b22b933Srs200217 verbosedebugf("SendResponses: Next in %ld ticks", m->NextScheduledResponse - m->timenow);
3327*4b22b933Srs200217 }
3328*4b22b933Srs200217
3329*4b22b933Srs200217 // Calling CheckCacheExpiration() is an expensive operation because it has to look at the entire cache,
3330*4b22b933Srs200217 // so we want to be lazy about how frequently we do it.
3331*4b22b933Srs200217 // 1. If a cache record is currently referenced by *no* active questions,
3332*4b22b933Srs200217 // then we don't mind expiring it up to a minute late (who will know?)
3333*4b22b933Srs200217 // 2. Else, if a cache record is due for some of its final expiration queries,
3334*4b22b933Srs200217 // we'll allow them to be late by up to 2% of the TTL
3335*4b22b933Srs200217 // 3. Else, if a cache record has completed all its final expiration queries without success,
3336*4b22b933Srs200217 // and is expiring, and had an original TTL more than ten seconds, we'll allow it to be one second late
3337*4b22b933Srs200217 // 4. Else, it is expiring and had an original TTL of ten seconds or less (includes explicit goodbye packets),
3338*4b22b933Srs200217 // so allow at most 1/10 second lateness
3339*4b22b933Srs200217 #define CacheCheckGracePeriod(RR) ( \
3340*4b22b933Srs200217 ((RR)->DelayDelivery ) ? (mDNSPlatformOneSecond/10) : \
3341*4b22b933Srs200217 ((RR)->CRActiveQuestion == mDNSNULL ) ? (60 * mDNSPlatformOneSecond) : \
3342*4b22b933Srs200217 ((RR)->UnansweredQueries < MaxUnansweredQueries) ? (TicksTTL(rr)/50) : \
3343*4b22b933Srs200217 ((RR)->resrec.rroriginalttl > 10 ) ? (mDNSPlatformOneSecond) : (mDNSPlatformOneSecond/10))
3344*4b22b933Srs200217
3345*4b22b933Srs200217 // Note: MUST call SetNextCacheCheckTime any time we change:
3346*4b22b933Srs200217 // rr->TimeRcvd
3347*4b22b933Srs200217 // rr->resrec.rroriginalttl
3348*4b22b933Srs200217 // rr->UnansweredQueries
3349*4b22b933Srs200217 // rr->CRActiveQuestion
3350*4b22b933Srs200217 // Also, any time we set rr->DelayDelivery we should call SetNextCacheCheckTime to ensure m->NextCacheCheck is set if necessary
3351*4b22b933Srs200217 // Clearing rr->DelayDelivery does not require a call to SetNextCacheCheckTime
SetNextCacheCheckTime(mDNS * const m,CacheRecord * const rr)3352*4b22b933Srs200217 mDNSlocal void SetNextCacheCheckTime(mDNS *const m, CacheRecord *const rr)
3353*4b22b933Srs200217 {
3354*4b22b933Srs200217 rr->NextRequiredQuery = RRExpireTime(rr);
3355*4b22b933Srs200217
3356*4b22b933Srs200217 // If we have an active question, then see if we want to schedule a refresher query for this record.
3357*4b22b933Srs200217 // Usually we expect to do four queries, at 80-82%, 85-87%, 90-92% and then 95-97% of the TTL.
3358*4b22b933Srs200217 if (rr->CRActiveQuestion && rr->UnansweredQueries < MaxUnansweredQueries)
3359*4b22b933Srs200217 {
3360*4b22b933Srs200217 rr->NextRequiredQuery -= TicksTTL(rr)/20 * (MaxUnansweredQueries - rr->UnansweredQueries);
3361*4b22b933Srs200217 rr->NextRequiredQuery += mDNSRandom((mDNSu32)TicksTTL(rr)/50);
3362*4b22b933Srs200217 verbosedebugf("SetNextCacheCheckTime: %##s (%s) NextRequiredQuery in %ld sec CacheCheckGracePeriod %d ticks",
3363*4b22b933Srs200217 rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype),
3364*4b22b933Srs200217 (rr->NextRequiredQuery - m->timenow) / mDNSPlatformOneSecond, CacheCheckGracePeriod(rr));
3365*4b22b933Srs200217 }
3366*4b22b933Srs200217
3367*4b22b933Srs200217 if (m->NextCacheCheck - (rr->NextRequiredQuery + CacheCheckGracePeriod(rr)) > 0)
3368*4b22b933Srs200217 m->NextCacheCheck = (rr->NextRequiredQuery + CacheCheckGracePeriod(rr));
3369*4b22b933Srs200217
3370*4b22b933Srs200217 if (rr->DelayDelivery)
3371*4b22b933Srs200217 if (m->NextCacheCheck - rr->DelayDelivery > 0)
3372*4b22b933Srs200217 m->NextCacheCheck = rr->DelayDelivery;
3373*4b22b933Srs200217 }
3374*4b22b933Srs200217
3375*4b22b933Srs200217 #define kMinimumReconfirmTime ((mDNSu32)mDNSPlatformOneSecond * 5)
3376*4b22b933Srs200217 #define kDefaultReconfirmTimeForWake ((mDNSu32)mDNSPlatformOneSecond * 5)
3377*4b22b933Srs200217 #define kDefaultReconfirmTimeForNoAnswer ((mDNSu32)mDNSPlatformOneSecond * 15)
3378*4b22b933Srs200217 #define kDefaultReconfirmTimeForFlappingInterface ((mDNSu32)mDNSPlatformOneSecond * 30)
3379*4b22b933Srs200217
mDNS_Reconfirm_internal(mDNS * const m,CacheRecord * const rr,mDNSu32 interval)3380*4b22b933Srs200217 mDNSlocal mStatus mDNS_Reconfirm_internal(mDNS *const m, CacheRecord *const rr, mDNSu32 interval)
3381*4b22b933Srs200217 {
3382*4b22b933Srs200217 if (interval < kMinimumReconfirmTime)
3383*4b22b933Srs200217 interval = kMinimumReconfirmTime;
3384*4b22b933Srs200217 if (interval > 0x10000000) // Make sure interval doesn't overflow when we multiply by four below
3385*4b22b933Srs200217 interval = 0x10000000;
3386*4b22b933Srs200217
3387*4b22b933Srs200217 // If the expected expiration time for this record is more than interval+33%, then accelerate its expiration
3388*4b22b933Srs200217 if (RRExpireTime(rr) - m->timenow > (mDNSs32)((interval * 4) / 3))
3389*4b22b933Srs200217 {
3390*4b22b933Srs200217 // Add a 33% random amount to the interval, to avoid synchronization between multiple hosts
3391*4b22b933Srs200217 // For all the reconfirmations in a given batch, we want to use the same random value
3392*4b22b933Srs200217 // so that the reconfirmation questions can be grouped into a single query packet
3393*4b22b933Srs200217 if (!m->RandomReconfirmDelay) m->RandomReconfirmDelay = 1 + mDNSRandom(0x3FFFFFFF);
3394*4b22b933Srs200217 interval += mDNSRandomFromFixedSeed(m->RandomReconfirmDelay, interval/3);
3395*4b22b933Srs200217 rr->TimeRcvd = m->timenow - (mDNSs32)interval * 3;
3396*4b22b933Srs200217 rr->resrec.rroriginalttl = (interval * 4 + mDNSPlatformOneSecond - 1) / mDNSPlatformOneSecond;
3397*4b22b933Srs200217 SetNextCacheCheckTime(m, rr);
3398*4b22b933Srs200217 }
3399*4b22b933Srs200217 debugf("mDNS_Reconfirm_internal:%6ld ticks to go for %s", RRExpireTime(rr) - m->timenow, CRDisplayString(m, rr));
3400*4b22b933Srs200217 return(mStatus_NoError);
3401*4b22b933Srs200217 }
3402*4b22b933Srs200217
3403*4b22b933Srs200217 #define MaxQuestionInterval (3600 * mDNSPlatformOneSecond)
3404*4b22b933Srs200217
3405*4b22b933Srs200217 // BuildQuestion puts a question into a DNS Query packet and if successful, updates the value of queryptr.
3406*4b22b933Srs200217 // It also appends to the list of known answer records that need to be included,
3407*4b22b933Srs200217 // and updates the forcast for the size of the known answer section.
BuildQuestion(mDNS * const m,DNSMessage * query,mDNSu8 ** queryptr,DNSQuestion * q,CacheRecord *** kalistptrptr,mDNSu32 * answerforecast)3408*4b22b933Srs200217 mDNSlocal mDNSBool BuildQuestion(mDNS *const m, DNSMessage *query, mDNSu8 **queryptr, DNSQuestion *q,
3409*4b22b933Srs200217 CacheRecord ***kalistptrptr, mDNSu32 *answerforecast)
3410*4b22b933Srs200217 {
3411*4b22b933Srs200217 mDNSBool ucast = (q->LargeAnswers || q->RequestUnicast) && m->CanReceiveUnicastOn5353;
3412*4b22b933Srs200217 mDNSu16 ucbit = (mDNSu16)(ucast ? kDNSQClass_UnicastResponse : 0);
3413*4b22b933Srs200217 const mDNSu8 *const limit = query->data + NormalMaxDNSMessageData;
3414*4b22b933Srs200217 mDNSu8 *newptr = putQuestion(query, *queryptr, limit, &q->qname, q->qtype, (mDNSu16)(q->qclass | ucbit));
3415*4b22b933Srs200217 if (!newptr)
3416*4b22b933Srs200217 {
3417*4b22b933Srs200217 debugf("BuildQuestion: No more space in this packet for question %##s", q->qname.c);
3418*4b22b933Srs200217 return(mDNSfalse);
3419*4b22b933Srs200217 }
3420*4b22b933Srs200217 else if (newptr + *answerforecast >= limit)
3421*4b22b933Srs200217 {
3422*4b22b933Srs200217 verbosedebugf("BuildQuestion: Retracting question %##s new forecast total %d",
3423*4b22b933Srs200217 q->qname.c, newptr + *answerforecast - query->data);
3424*4b22b933Srs200217 query->h.numQuestions--;
3425*4b22b933Srs200217 return(mDNSfalse);
3426*4b22b933Srs200217 }
3427*4b22b933Srs200217 else
3428*4b22b933Srs200217 {
3429*4b22b933Srs200217 mDNSu32 forecast = *answerforecast;
3430*4b22b933Srs200217 const mDNSu32 slot = HashSlot(&q->qname);
3431*4b22b933Srs200217 CacheGroup *cg = CacheGroupForName(m, slot, q->qnamehash, &q->qname);
3432*4b22b933Srs200217 CacheRecord *rr;
3433*4b22b933Srs200217 CacheRecord **ka = *kalistptrptr; // Make a working copy of the pointer we're going to update
3434*4b22b933Srs200217
3435*4b22b933Srs200217 for (rr = cg ? cg->members : mDNSNULL; rr; rr=rr->next) // If we have a resource record in our cache,
3436*4b22b933Srs200217 if (rr->resrec.InterfaceID == q->SendQNow && // received on this interface
3437*4b22b933Srs200217 rr->NextInKAList == mDNSNULL && ka != &rr->NextInKAList && // which is not already in the known answer list
3438*4b22b933Srs200217 rr->resrec.rdlength <= SmallRecordLimit && // which is small enough to sensibly fit in the packet
3439*4b22b933Srs200217 ResourceRecordAnswersQuestion(&rr->resrec, q) && // which answers our question
3440*4b22b933Srs200217 rr->TimeRcvd + TicksTTL(rr)/2 - m->timenow > // and its half-way-to-expiry time is at least 1 second away
3441*4b22b933Srs200217 mDNSPlatformOneSecond) // (also ensures we never include goodbye records with TTL=1)
3442*4b22b933Srs200217 {
3443*4b22b933Srs200217 *ka = rr; // Link this record into our known answer chain
3444*4b22b933Srs200217 ka = &rr->NextInKAList;
3445*4b22b933Srs200217 // We forecast: compressed name (2) type (2) class (2) TTL (4) rdlength (2) rdata (n)
3446*4b22b933Srs200217 forecast += 12 + rr->resrec.rdestimate;
3447*4b22b933Srs200217 // If we're trying to put more than one question in this packet, and it doesn't fit
3448*4b22b933Srs200217 // then undo that last question and try again next time
3449*4b22b933Srs200217 if (query->h.numQuestions > 1 && newptr + forecast >= limit)
3450*4b22b933Srs200217 {
3451*4b22b933Srs200217 debugf("BuildQuestion: Retracting question %##s (%s) new forecast total %d",
3452*4b22b933Srs200217 q->qname.c, DNSTypeName(q->qtype), newptr + forecast - query->data);
3453*4b22b933Srs200217 query->h.numQuestions--;
3454*4b22b933Srs200217 ka = *kalistptrptr; // Go back to where we started and retract these answer records
3455*4b22b933Srs200217 while (*ka) { CacheRecord *rr = *ka; *ka = mDNSNULL; ka = &rr->NextInKAList; }
3456*4b22b933Srs200217 return(mDNSfalse); // Return false, so we'll try again in the next packet
3457*4b22b933Srs200217 }
3458*4b22b933Srs200217 }
3459*4b22b933Srs200217
3460*4b22b933Srs200217 // Traffic reduction:
3461*4b22b933Srs200217 // If we already have at least one unique answer in the cache,
3462*4b22b933Srs200217 // OR we have so many shared answers that the KA list is too big to fit in one packet
3463*4b22b933Srs200217 // The we suppress queries number 3 and 5:
3464*4b22b933Srs200217 // Query 1 (immediately; ThisQInterval = 1 sec; request unicast replies)
3465*4b22b933Srs200217 // Query 2 (after 1 second; ThisQInterval = 2 sec; send normally)
3466*4b22b933Srs200217 // Query 3 (after 2 seconds; ThisQInterval = 4 sec; may suppress)
3467*4b22b933Srs200217 // Query 4 (after 4 seconds; ThisQInterval = 8 sec; send normally)
3468*4b22b933Srs200217 // Query 5 (after 8 seconds; ThisQInterval = 16 sec; may suppress)
3469*4b22b933Srs200217 // Query 6 (after 16 seconds; ThisQInterval = 32 sec; send normally)
3470*4b22b933Srs200217 if (q->UniqueAnswers || newptr + forecast >= limit)
3471*4b22b933Srs200217 if (q->ThisQInterval == InitialQuestionInterval * 8 || q->ThisQInterval == InitialQuestionInterval * 32)
3472*4b22b933Srs200217 {
3473*4b22b933Srs200217 query->h.numQuestions--;
3474*4b22b933Srs200217 ka = *kalistptrptr; // Go back to where we started and retract these answer records
3475*4b22b933Srs200217 while (*ka) { CacheRecord *rr = *ka; *ka = mDNSNULL; ka = &rr->NextInKAList; }
3476*4b22b933Srs200217 return(mDNStrue); // Return true: pretend we succeeded, even though we actually suppressed this question
3477*4b22b933Srs200217 }
3478*4b22b933Srs200217
3479*4b22b933Srs200217 // Success! Update our state pointers, increment UnansweredQueries as appropriate, and return
3480*4b22b933Srs200217 *queryptr = newptr; // Update the packet pointer
3481*4b22b933Srs200217 *answerforecast = forecast; // Update the forecast
3482*4b22b933Srs200217 *kalistptrptr = ka; // Update the known answer list pointer
3483*4b22b933Srs200217 if (ucast) m->ExpectUnicastResponse = m->timenow;
3484*4b22b933Srs200217
3485*4b22b933Srs200217 for (rr = cg ? cg->members : mDNSNULL; rr; rr=rr->next) // For every resource record in our cache,
3486*4b22b933Srs200217 if (rr->resrec.InterfaceID == q->SendQNow && // received on this interface
3487*4b22b933Srs200217 rr->NextInKAList == mDNSNULL && ka != &rr->NextInKAList && // which is not in the known answer list
3488*4b22b933Srs200217 ResourceRecordAnswersQuestion(&rr->resrec, q)) // which answers our question
3489*4b22b933Srs200217 {
3490*4b22b933Srs200217 rr->UnansweredQueries++; // indicate that we're expecting a response
3491*4b22b933Srs200217 rr->LastUnansweredTime = m->timenow;
3492*4b22b933Srs200217 SetNextCacheCheckTime(m, rr);
3493*4b22b933Srs200217 }
3494*4b22b933Srs200217
3495*4b22b933Srs200217 return(mDNStrue);
3496*4b22b933Srs200217 }
3497*4b22b933Srs200217 }
3498*4b22b933Srs200217
ReconfirmAntecedents(mDNS * const m,DNSQuestion * q)3499*4b22b933Srs200217 mDNSlocal void ReconfirmAntecedents(mDNS *const m, DNSQuestion *q)
3500*4b22b933Srs200217 {
3501*4b22b933Srs200217 mDNSu32 slot;
3502*4b22b933Srs200217 CacheGroup *cg;
3503*4b22b933Srs200217 CacheRecord *rr;
3504*4b22b933Srs200217 domainname *target;
3505*4b22b933Srs200217 FORALL_CACHERECORDS(slot, cg, rr)
3506*4b22b933Srs200217 if ((target = GetRRDomainNameTarget(&rr->resrec)) && rr->resrec.rdatahash == q->qnamehash && SameDomainName(target, &q->qname))
3507*4b22b933Srs200217 mDNS_Reconfirm_internal(m, rr, kDefaultReconfirmTimeForNoAnswer);
3508*4b22b933Srs200217 }
3509*4b22b933Srs200217
3510*4b22b933Srs200217 // Only DupSuppressInfos newer than the specified 'time' are allowed to remain active
ExpireDupSuppressInfo(DupSuppressInfo ds[DupSuppressInfoSize],mDNSs32 time)3511*4b22b933Srs200217 mDNSlocal void ExpireDupSuppressInfo(DupSuppressInfo ds[DupSuppressInfoSize], mDNSs32 time)
3512*4b22b933Srs200217 {
3513*4b22b933Srs200217 int i;
3514*4b22b933Srs200217 for (i=0; i<DupSuppressInfoSize; i++) if (ds[i].Time - time < 0) ds[i].InterfaceID = mDNSNULL;
3515*4b22b933Srs200217 }
3516*4b22b933Srs200217
ExpireDupSuppressInfoOnInterface(DupSuppressInfo ds[DupSuppressInfoSize],mDNSs32 time,mDNSInterfaceID InterfaceID)3517*4b22b933Srs200217 mDNSlocal void ExpireDupSuppressInfoOnInterface(DupSuppressInfo ds[DupSuppressInfoSize], mDNSs32 time, mDNSInterfaceID InterfaceID)
3518*4b22b933Srs200217 {
3519*4b22b933Srs200217 int i;
3520*4b22b933Srs200217 for (i=0; i<DupSuppressInfoSize; i++) if (ds[i].InterfaceID == InterfaceID && ds[i].Time - time < 0) ds[i].InterfaceID = mDNSNULL;
3521*4b22b933Srs200217 }
3522*4b22b933Srs200217
SuppressOnThisInterface(const DupSuppressInfo ds[DupSuppressInfoSize],const NetworkInterfaceInfo * const intf)3523*4b22b933Srs200217 mDNSlocal mDNSBool SuppressOnThisInterface(const DupSuppressInfo ds[DupSuppressInfoSize], const NetworkInterfaceInfo * const intf)
3524*4b22b933Srs200217 {
3525*4b22b933Srs200217 int i;
3526*4b22b933Srs200217 mDNSBool v4 = !intf->IPv4Available; // If this interface doesn't do v4, we don't need to find a v4 duplicate of this query
3527*4b22b933Srs200217 mDNSBool v6 = !intf->IPv6Available; // If this interface doesn't do v6, we don't need to find a v6 duplicate of this query
3528*4b22b933Srs200217 for (i=0; i<DupSuppressInfoSize; i++)
3529*4b22b933Srs200217 if (ds[i].InterfaceID == intf->InterfaceID)
3530*4b22b933Srs200217 {
3531*4b22b933Srs200217 if (ds[i].Type == mDNSAddrType_IPv4) v4 = mDNStrue;
3532*4b22b933Srs200217 else if (ds[i].Type == mDNSAddrType_IPv6) v6 = mDNStrue;
3533*4b22b933Srs200217 if (v4 && v6) return(mDNStrue);
3534*4b22b933Srs200217 }
3535*4b22b933Srs200217 return(mDNSfalse);
3536*4b22b933Srs200217 }
3537*4b22b933Srs200217
RecordDupSuppressInfo(DupSuppressInfo ds[DupSuppressInfoSize],mDNSs32 Time,mDNSInterfaceID InterfaceID,mDNSs32 Type)3538*4b22b933Srs200217 mDNSlocal int RecordDupSuppressInfo(DupSuppressInfo ds[DupSuppressInfoSize], mDNSs32 Time, mDNSInterfaceID InterfaceID, mDNSs32 Type)
3539*4b22b933Srs200217 {
3540*4b22b933Srs200217 int i, j;
3541*4b22b933Srs200217
3542*4b22b933Srs200217 // See if we have this one in our list somewhere already
3543*4b22b933Srs200217 for (i=0; i<DupSuppressInfoSize; i++) if (ds[i].InterfaceID == InterfaceID && ds[i].Type == Type) break;
3544*4b22b933Srs200217
3545*4b22b933Srs200217 // If not, find a slot we can re-use
3546*4b22b933Srs200217 if (i >= DupSuppressInfoSize)
3547*4b22b933Srs200217 {
3548*4b22b933Srs200217 i = 0;
3549*4b22b933Srs200217 for (j=1; j<DupSuppressInfoSize && ds[i].InterfaceID; j++)
3550*4b22b933Srs200217 if (!ds[j].InterfaceID || ds[j].Time - ds[i].Time < 0)
3551*4b22b933Srs200217 i = j;
3552*4b22b933Srs200217 }
3553*4b22b933Srs200217
3554*4b22b933Srs200217 // Record the info about this query we saw
3555*4b22b933Srs200217 ds[i].Time = Time;
3556*4b22b933Srs200217 ds[i].InterfaceID = InterfaceID;
3557*4b22b933Srs200217 ds[i].Type = Type;
3558*4b22b933Srs200217
3559*4b22b933Srs200217 return(i);
3560*4b22b933Srs200217 }
3561*4b22b933Srs200217
AccelerateThisQuery(mDNS * const m,DNSQuestion * q)3562*4b22b933Srs200217 mDNSlocal mDNSBool AccelerateThisQuery(mDNS *const m, DNSQuestion *q)
3563*4b22b933Srs200217 {
3564*4b22b933Srs200217 // If more than 90% of the way to the query time, we should unconditionally accelerate it
3565*4b22b933Srs200217 if (TimeToSendThisQuestion(q, m->timenow + q->ThisQInterval/10))
3566*4b22b933Srs200217 return(mDNStrue);
3567*4b22b933Srs200217
3568*4b22b933Srs200217 // If half-way to next scheduled query time, only accelerate if it will add less than 512 bytes to the packet
3569*4b22b933Srs200217 if (TimeToSendThisQuestion(q, m->timenow + q->ThisQInterval/2))
3570*4b22b933Srs200217 {
3571*4b22b933Srs200217 // We forecast: qname (n) type (2) class (2)
3572*4b22b933Srs200217 mDNSu32 forecast = (mDNSu32)DomainNameLength(&q->qname) + 4;
3573*4b22b933Srs200217 const mDNSu32 slot = HashSlot(&q->qname);
3574*4b22b933Srs200217 CacheGroup *cg = CacheGroupForName(m, slot, q->qnamehash, &q->qname);
3575*4b22b933Srs200217 CacheRecord *rr;
3576*4b22b933Srs200217 for (rr = cg ? cg->members : mDNSNULL; rr; rr=rr->next) // If we have a resource record in our cache,
3577*4b22b933Srs200217 if (rr->resrec.rdlength <= SmallRecordLimit && // which is small enough to sensibly fit in the packet
3578*4b22b933Srs200217 ResourceRecordAnswersQuestion(&rr->resrec, q) && // which answers our question
3579*4b22b933Srs200217 rr->TimeRcvd + TicksTTL(rr)/2 - m->timenow >= 0 && // and it is less than half-way to expiry
3580*4b22b933Srs200217 rr->NextRequiredQuery - (m->timenow + q->ThisQInterval) > 0)// and we'll ask at least once again before NextRequiredQuery
3581*4b22b933Srs200217 {
3582*4b22b933Srs200217 // We forecast: compressed name (2) type (2) class (2) TTL (4) rdlength (2) rdata (n)
3583*4b22b933Srs200217 forecast += 12 + rr->resrec.rdestimate;
3584*4b22b933Srs200217 if (forecast >= 512) return(mDNSfalse); // If this would add 512 bytes or more to the packet, don't accelerate
3585*4b22b933Srs200217 }
3586*4b22b933Srs200217 return(mDNStrue);
3587*4b22b933Srs200217 }
3588*4b22b933Srs200217
3589*4b22b933Srs200217 return(mDNSfalse);
3590*4b22b933Srs200217 }
3591*4b22b933Srs200217
3592*4b22b933Srs200217 // How Standard Queries are generated:
3593*4b22b933Srs200217 // 1. The Question Section contains the question
3594*4b22b933Srs200217 // 2. The Additional Section contains answers we already know, to suppress duplicate responses
3595*4b22b933Srs200217
3596*4b22b933Srs200217 // How Probe Queries are generated:
3597*4b22b933Srs200217 // 1. The Question Section contains queries for the name we intend to use, with QType=ANY because
3598*4b22b933Srs200217 // if some other host is already using *any* records with this name, we want to know about it.
3599*4b22b933Srs200217 // 2. The Authority Section contains the proposed values we intend to use for one or more
3600*4b22b933Srs200217 // of our records with that name (analogous to the Update section of DNS Update packets)
3601*4b22b933Srs200217 // because if some other host is probing at the same time, we each want to know what the other is
3602*4b22b933Srs200217 // planning, in order to apply the tie-breaking rule to see who gets to use the name and who doesn't.
3603*4b22b933Srs200217
SendQueries(mDNS * const m)3604*4b22b933Srs200217 mDNSlocal void SendQueries(mDNS *const m)
3605*4b22b933Srs200217 {
3606*4b22b933Srs200217 mDNSu32 slot;
3607*4b22b933Srs200217 CacheGroup *cg;
3608*4b22b933Srs200217 CacheRecord *cr;
3609*4b22b933Srs200217 AuthRecord *ar;
3610*4b22b933Srs200217 int pktcount = 0;
3611*4b22b933Srs200217 DNSQuestion *q;
3612*4b22b933Srs200217 // For explanation of maxExistingQuestionInterval logic, see comments for maxExistingAnnounceInterval
3613*4b22b933Srs200217 mDNSs32 maxExistingQuestionInterval = 0;
3614*4b22b933Srs200217 const NetworkInterfaceInfo *intf = GetFirstActiveInterface(m->HostInterfaces);
3615*4b22b933Srs200217 CacheRecord *KnownAnswerList = mDNSNULL;
3616*4b22b933Srs200217
3617*4b22b933Srs200217 // 1. If time for a query, work out what we need to do
3618*4b22b933Srs200217 if (m->timenow - m->NextScheduledQuery >= 0)
3619*4b22b933Srs200217 {
3620*4b22b933Srs200217 CacheRecord *rr;
3621*4b22b933Srs200217 m->NextScheduledQuery = m->timenow + 0x78000000;
3622*4b22b933Srs200217
3623*4b22b933Srs200217 // We're expecting to send a query anyway, so see if any expiring cache records are close enough
3624*4b22b933Srs200217 // to their NextRequiredQuery to be worth batching them together with this one
3625*4b22b933Srs200217 FORALL_CACHERECORDS(slot, cg, rr)
3626*4b22b933Srs200217 if (rr->CRActiveQuestion && rr->UnansweredQueries < MaxUnansweredQueries)
3627*4b22b933Srs200217 if (m->timenow + TicksTTL(rr)/50 - rr->NextRequiredQuery >= 0)
3628*4b22b933Srs200217 {
3629*4b22b933Srs200217 q = rr->CRActiveQuestion;
3630*4b22b933Srs200217 ExpireDupSuppressInfoOnInterface(q->DupSuppress, m->timenow - TicksTTL(rr)/20, rr->resrec.InterfaceID);
3631*4b22b933Srs200217 if (q->Target.type) q->SendQNow = mDNSInterfaceMark; // If unicast query, mark it
3632*4b22b933Srs200217 else if (q->SendQNow == mDNSNULL) q->SendQNow = rr->resrec.InterfaceID;
3633*4b22b933Srs200217 else if (q->SendQNow != rr->resrec.InterfaceID) q->SendQNow = mDNSInterfaceMark;
3634*4b22b933Srs200217 }
3635*4b22b933Srs200217
3636*4b22b933Srs200217 // Scan our list of questions to see which *unicast* queries need to be sent
3637*4b22b933Srs200217 for (q = m->Questions; q; q=q->next)
3638*4b22b933Srs200217 if (q->Target.type && (q->SendQNow || TimeToSendThisQuestion(q, m->timenow)))
3639*4b22b933Srs200217 {
3640*4b22b933Srs200217 mDNSu8 *qptr = m->omsg.data;
3641*4b22b933Srs200217 const mDNSu8 *const limit = m->omsg.data + sizeof(m->omsg.data);
3642*4b22b933Srs200217 InitializeDNSMessage(&m->omsg.h, q->TargetQID, QueryFlags);
3643*4b22b933Srs200217 qptr = putQuestion(&m->omsg, qptr, limit, &q->qname, q->qtype, q->qclass);
3644*4b22b933Srs200217 mDNSSendDNSMessage(m, &m->omsg, qptr, mDNSInterface_Any, &q->Target, q->TargetPort, -1, mDNSNULL);
3645*4b22b933Srs200217 q->ThisQInterval *= 2;
3646*4b22b933Srs200217 if (q->ThisQInterval > MaxQuestionInterval)
3647*4b22b933Srs200217 q->ThisQInterval = MaxQuestionInterval;
3648*4b22b933Srs200217 q->LastQTime = m->timenow;
3649*4b22b933Srs200217 q->LastQTxTime = m->timenow;
3650*4b22b933Srs200217 q->RecentAnswerPkts = 0;
3651*4b22b933Srs200217 q->SendQNow = mDNSNULL;
3652*4b22b933Srs200217 m->ExpectUnicastResponse = m->timenow;
3653*4b22b933Srs200217 }
3654*4b22b933Srs200217
3655*4b22b933Srs200217 // Scan our list of questions to see which *multicast* queries we're definitely going to send
3656*4b22b933Srs200217 for (q = m->Questions; q; q=q->next)
3657*4b22b933Srs200217 if (!q->Target.type && TimeToSendThisQuestion(q, m->timenow))
3658*4b22b933Srs200217 {
3659*4b22b933Srs200217 q->SendQNow = mDNSInterfaceMark; // Mark this question for sending on all interfaces
3660*4b22b933Srs200217 if (maxExistingQuestionInterval < q->ThisQInterval)
3661*4b22b933Srs200217 maxExistingQuestionInterval = q->ThisQInterval;
3662*4b22b933Srs200217 }
3663*4b22b933Srs200217
3664*4b22b933Srs200217 // Scan our list of questions
3665*4b22b933Srs200217 // (a) to see if there are any more that are worth accelerating, and
3666*4b22b933Srs200217 // (b) to update the state variables for *all* the questions we're going to send
3667*4b22b933Srs200217 for (q = m->Questions; q; q=q->next)
3668*4b22b933Srs200217 {
3669*4b22b933Srs200217 if (q->SendQNow ||
3670*4b22b933Srs200217 (!q->Target.type && ActiveQuestion(q) && q->ThisQInterval <= maxExistingQuestionInterval && AccelerateThisQuery(m,q)))
3671*4b22b933Srs200217 {
3672*4b22b933Srs200217 // If at least halfway to next query time, advance to next interval
3673*4b22b933Srs200217 // If less than halfway to next query time, then
3674*4b22b933Srs200217 // treat this as logically a repeat of the last transmission, without advancing the interval
3675*4b22b933Srs200217 if (m->timenow - (q->LastQTime + q->ThisQInterval/2) >= 0)
3676*4b22b933Srs200217 {
3677*4b22b933Srs200217 q->SendQNow = mDNSInterfaceMark; // Mark this question for sending on all interfaces
3678*4b22b933Srs200217 q->ThisQInterval *= 2;
3679*4b22b933Srs200217 if (q->ThisQInterval > MaxQuestionInterval)
3680*4b22b933Srs200217 q->ThisQInterval = MaxQuestionInterval;
3681*4b22b933Srs200217 else if (q->CurrentAnswers == 0 && q->ThisQInterval == InitialQuestionInterval * 8)
3682*4b22b933Srs200217 {
3683*4b22b933Srs200217 debugf("SendQueries: Zero current answers for %##s (%s); will reconfirm antecedents",
3684*4b22b933Srs200217 q->qname.c, DNSTypeName(q->qtype));
3685*4b22b933Srs200217 ReconfirmAntecedents(m, q); // Sending third query, and no answers yet; time to begin doubting the source
3686*4b22b933Srs200217 }
3687*4b22b933Srs200217 }
3688*4b22b933Srs200217
3689*4b22b933Srs200217 // Mark for sending. (If no active interfaces, then don't even try.)
3690*4b22b933Srs200217 q->SendOnAll = (q->SendQNow == mDNSInterfaceMark);
3691*4b22b933Srs200217 if (q->SendOnAll)
3692*4b22b933Srs200217 {
3693*4b22b933Srs200217 q->SendQNow = !intf ? mDNSNULL : (q->InterfaceID) ? q->InterfaceID : intf->InterfaceID;
3694*4b22b933Srs200217 q->LastQTime = m->timenow;
3695*4b22b933Srs200217 }
3696*4b22b933Srs200217
3697*4b22b933Srs200217 // If we recorded a duplicate suppression for this question less than half an interval ago,
3698*4b22b933Srs200217 // then we consider it recent enough that we don't need to do an identical query ourselves.
3699*4b22b933Srs200217 ExpireDupSuppressInfo(q->DupSuppress, m->timenow - q->ThisQInterval/2);
3700*4b22b933Srs200217
3701*4b22b933Srs200217 q->LastQTxTime = m->timenow;
3702*4b22b933Srs200217 q->RecentAnswerPkts = 0;
3703*4b22b933Srs200217 if (q->RequestUnicast) q->RequestUnicast--;
3704*4b22b933Srs200217 }
3705*4b22b933Srs200217 // For all questions (not just the ones we're sending) check what the next scheduled event will be
3706*4b22b933Srs200217 SetNextQueryTime(m,q);
3707*4b22b933Srs200217 }
3708*4b22b933Srs200217 }
3709*4b22b933Srs200217
3710*4b22b933Srs200217 // 2. Scan our authoritative RR list to see what probes we might need to send
3711*4b22b933Srs200217 if (m->timenow - m->NextScheduledProbe >= 0)
3712*4b22b933Srs200217 {
3713*4b22b933Srs200217 m->NextScheduledProbe = m->timenow + 0x78000000;
3714*4b22b933Srs200217
3715*4b22b933Srs200217 if (m->CurrentRecord) LogMsg("SendQueries: ERROR m->CurrentRecord already set");
3716*4b22b933Srs200217 m->CurrentRecord = m->ResourceRecords;
3717*4b22b933Srs200217 while (m->CurrentRecord)
3718*4b22b933Srs200217 {
3719*4b22b933Srs200217 AuthRecord *rr = m->CurrentRecord;
3720*4b22b933Srs200217 m->CurrentRecord = rr->next;
3721*4b22b933Srs200217 if (rr->resrec.RecordType == kDNSRecordTypeUnique) // For all records that are still probing...
3722*4b22b933Srs200217 {
3723*4b22b933Srs200217 // 1. If it's not reached its probe time, just make sure we update m->NextScheduledProbe correctly
3724*4b22b933Srs200217 if (m->timenow - (rr->LastAPTime + rr->ThisAPInterval) < 0)
3725*4b22b933Srs200217 {
3726*4b22b933Srs200217 SetNextAnnounceProbeTime(m, rr);
3727*4b22b933Srs200217 }
3728*4b22b933Srs200217 // 2. else, if it has reached its probe time, mark it for sending and then update m->NextScheduledProbe correctly
3729*4b22b933Srs200217 else if (rr->ProbeCount)
3730*4b22b933Srs200217 {
3731*4b22b933Srs200217 // Mark for sending. (If no active interfaces, then don't even try.)
3732*4b22b933Srs200217 rr->SendRNow = !intf ? mDNSNULL : (rr->resrec.InterfaceID) ? rr->resrec.InterfaceID : intf->InterfaceID;
3733*4b22b933Srs200217 rr->LastAPTime = m->timenow;
3734*4b22b933Srs200217 rr->ProbeCount--;
3735*4b22b933Srs200217 SetNextAnnounceProbeTime(m, rr);
3736*4b22b933Srs200217 }
3737*4b22b933Srs200217 // else, if it has now finished probing, move it to state Verified,
3738*4b22b933Srs200217 // and update m->NextScheduledResponse so it will be announced
3739*4b22b933Srs200217 else
3740*4b22b933Srs200217 {
3741*4b22b933Srs200217 AuthRecord *r2;
3742*4b22b933Srs200217 rr->resrec.RecordType = kDNSRecordTypeVerified;
3743*4b22b933Srs200217 rr->ThisAPInterval = DefaultAnnounceIntervalForTypeUnique;
3744*4b22b933Srs200217 rr->LastAPTime = m->timenow - DefaultAnnounceIntervalForTypeUnique;
3745*4b22b933Srs200217 SetNextAnnounceProbeTime(m, rr);
3746*4b22b933Srs200217 // If we have any records on our duplicate list that match this one, they have now also completed probing
3747*4b22b933Srs200217 for (r2 = m->DuplicateRecords; r2; r2=r2->next)
3748*4b22b933Srs200217 if (r2->resrec.RecordType == kDNSRecordTypeUnique && RecordIsLocalDuplicate(r2, rr))
3749*4b22b933Srs200217 r2->ProbeCount = 0;
3750*4b22b933Srs200217 AcknowledgeRecord(m, rr);
3751*4b22b933Srs200217 }
3752*4b22b933Srs200217 }
3753*4b22b933Srs200217 }
3754*4b22b933Srs200217 m->CurrentRecord = m->DuplicateRecords;
3755*4b22b933Srs200217 while (m->CurrentRecord)
3756*4b22b933Srs200217 {
3757*4b22b933Srs200217 AuthRecord *rr = m->CurrentRecord;
3758*4b22b933Srs200217 m->CurrentRecord = rr->next;
3759*4b22b933Srs200217 if (rr->resrec.RecordType == kDNSRecordTypeUnique && rr->ProbeCount == 0)
3760*4b22b933Srs200217 AcknowledgeRecord(m, rr);
3761*4b22b933Srs200217 }
3762*4b22b933Srs200217 }
3763*4b22b933Srs200217
3764*4b22b933Srs200217 // 3. Now we know which queries and probes we're sending,
3765*4b22b933Srs200217 // go through our interface list sending the appropriate queries on each interface
3766*4b22b933Srs200217 while (intf)
3767*4b22b933Srs200217 {
3768*4b22b933Srs200217 AuthRecord *rr;
3769*4b22b933Srs200217 mDNSu8 *queryptr = m->omsg.data;
3770*4b22b933Srs200217 InitializeDNSMessage(&m->omsg.h, zeroID, QueryFlags);
3771*4b22b933Srs200217 if (KnownAnswerList) verbosedebugf("SendQueries: KnownAnswerList set... Will continue from previous packet");
3772*4b22b933Srs200217 if (!KnownAnswerList)
3773*4b22b933Srs200217 {
3774*4b22b933Srs200217 // Start a new known-answer list
3775*4b22b933Srs200217 CacheRecord **kalistptr = &KnownAnswerList;
3776*4b22b933Srs200217 mDNSu32 answerforecast = 0;
3777*4b22b933Srs200217
3778*4b22b933Srs200217 // Put query questions in this packet
3779*4b22b933Srs200217 for (q = m->Questions; q; q=q->next)
3780*4b22b933Srs200217 if (q->SendQNow == intf->InterfaceID)
3781*4b22b933Srs200217 {
3782*4b22b933Srs200217 debugf("SendQueries: %s question for %##s (%s) at %d forecast total %d",
3783*4b22b933Srs200217 SuppressOnThisInterface(q->DupSuppress, intf) ? "Suppressing" : "Putting ",
3784*4b22b933Srs200217 q->qname.c, DNSTypeName(q->qtype), queryptr - m->omsg.data, queryptr + answerforecast - m->omsg.data);
3785*4b22b933Srs200217 // If we're suppressing this question, or we successfully put it, update its SendQNow state
3786*4b22b933Srs200217 if (SuppressOnThisInterface(q->DupSuppress, intf) ||
3787*4b22b933Srs200217 BuildQuestion(m, &m->omsg, &queryptr, q, &kalistptr, &answerforecast))
3788*4b22b933Srs200217 q->SendQNow = (q->InterfaceID || !q->SendOnAll) ? mDNSNULL : GetNextActiveInterfaceID(intf);
3789*4b22b933Srs200217 }
3790*4b22b933Srs200217
3791*4b22b933Srs200217 // Put probe questions in this packet
3792*4b22b933Srs200217 for (rr = m->ResourceRecords; rr; rr=rr->next)
3793*4b22b933Srs200217 if (rr->SendRNow == intf->InterfaceID)
3794*4b22b933Srs200217 {
3795*4b22b933Srs200217 mDNSBool ucast = (rr->ProbeCount >= DefaultProbeCountForTypeUnique-1) && m->CanReceiveUnicastOn5353;
3796*4b22b933Srs200217 mDNSu16 ucbit = (mDNSu16)(ucast ? kDNSQClass_UnicastResponse : 0);
3797*4b22b933Srs200217 const mDNSu8 *const limit = m->omsg.data + ((m->omsg.h.numQuestions) ? NormalMaxDNSMessageData : AbsoluteMaxDNSMessageData);
3798*4b22b933Srs200217 mDNSu8 *newptr = putQuestion(&m->omsg, queryptr, limit, rr->resrec.name, kDNSQType_ANY, (mDNSu16)(rr->resrec.rrclass | ucbit));
3799*4b22b933Srs200217 // We forecast: compressed name (2) type (2) class (2) TTL (4) rdlength (2) rdata (n)
3800*4b22b933Srs200217 mDNSu32 forecast = answerforecast + 12 + rr->resrec.rdestimate;
3801*4b22b933Srs200217 if (newptr && newptr + forecast < limit)
3802*4b22b933Srs200217 {
3803*4b22b933Srs200217 queryptr = newptr;
3804*4b22b933Srs200217 answerforecast = forecast;
3805*4b22b933Srs200217 rr->SendRNow = (rr->resrec.InterfaceID) ? mDNSNULL : GetNextActiveInterfaceID(intf);
3806*4b22b933Srs200217 rr->IncludeInProbe = mDNStrue;
3807*4b22b933Srs200217 verbosedebugf("SendQueries: Put Question %##s (%s) probecount %d",
3808*4b22b933Srs200217 rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype), rr->ProbeCount);
3809*4b22b933Srs200217 }
3810*4b22b933Srs200217 else
3811*4b22b933Srs200217 {
3812*4b22b933Srs200217 verbosedebugf("SendQueries: Retracting Question %##s (%s)",
3813*4b22b933Srs200217 rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype));
3814*4b22b933Srs200217 m->omsg.h.numQuestions--;
3815*4b22b933Srs200217 }
3816*4b22b933Srs200217 }
3817*4b22b933Srs200217 }
3818*4b22b933Srs200217
3819*4b22b933Srs200217 // Put our known answer list (either new one from this question or questions, or remainder of old one from last time)
3820*4b22b933Srs200217 while (KnownAnswerList)
3821*4b22b933Srs200217 {
3822*4b22b933Srs200217 CacheRecord *rr = KnownAnswerList;
3823*4b22b933Srs200217 mDNSu32 SecsSinceRcvd = ((mDNSu32)(m->timenow - rr->TimeRcvd)) / mDNSPlatformOneSecond;
3824*4b22b933Srs200217 mDNSu8 *newptr = PutResourceRecordTTL(&m->omsg, queryptr, &m->omsg.h.numAnswers, &rr->resrec, rr->resrec.rroriginalttl - SecsSinceRcvd);
3825*4b22b933Srs200217 if (newptr)
3826*4b22b933Srs200217 {
3827*4b22b933Srs200217 verbosedebugf("SendQueries: Put %##s (%s) at %d - %d",
3828*4b22b933Srs200217 rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype), queryptr - m->omsg.data, newptr - m->omsg.data);
3829*4b22b933Srs200217 queryptr = newptr;
3830*4b22b933Srs200217 KnownAnswerList = rr->NextInKAList;
3831*4b22b933Srs200217 rr->NextInKAList = mDNSNULL;
3832*4b22b933Srs200217 }
3833*4b22b933Srs200217 else
3834*4b22b933Srs200217 {
3835*4b22b933Srs200217 // If we ran out of space and we have more than one question in the packet, that's an error --
3836*4b22b933Srs200217 // we shouldn't have put more than one question if there was a risk of us running out of space.
3837*4b22b933Srs200217 if (m->omsg.h.numQuestions > 1)
3838*4b22b933Srs200217 LogMsg("SendQueries: Put %d answers; No more space for known answers", m->omsg.h.numAnswers);
3839*4b22b933Srs200217 m->omsg.h.flags.b[0] |= kDNSFlag0_TC;
3840*4b22b933Srs200217 break;
3841*4b22b933Srs200217 }
3842*4b22b933Srs200217 }
3843*4b22b933Srs200217
3844*4b22b933Srs200217 for (rr = m->ResourceRecords; rr; rr=rr->next)
3845*4b22b933Srs200217 if (rr->IncludeInProbe)
3846*4b22b933Srs200217 {
3847*4b22b933Srs200217 mDNSu8 *newptr = PutResourceRecord(&m->omsg, queryptr, &m->omsg.h.numAuthorities, &rr->resrec);
3848*4b22b933Srs200217 rr->IncludeInProbe = mDNSfalse;
3849*4b22b933Srs200217 if (newptr) queryptr = newptr;
3850*4b22b933Srs200217 else LogMsg("SendQueries: How did we fail to have space for the Update record %##s (%s)?",
3851*4b22b933Srs200217 rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype));
3852*4b22b933Srs200217 }
3853*4b22b933Srs200217
3854*4b22b933Srs200217 if (queryptr > m->omsg.data)
3855*4b22b933Srs200217 {
3856*4b22b933Srs200217 if ((m->omsg.h.flags.b[0] & kDNSFlag0_TC) && m->omsg.h.numQuestions > 1)
3857*4b22b933Srs200217 LogMsg("SendQueries: Should not have more than one question (%d) in a truncated packet", m->omsg.h.numQuestions);
3858*4b22b933Srs200217 debugf("SendQueries: Sending %d Question%s %d Answer%s %d Update%s on %p",
3859*4b22b933Srs200217 m->omsg.h.numQuestions, m->omsg.h.numQuestions == 1 ? "" : "s",
3860*4b22b933Srs200217 m->omsg.h.numAnswers, m->omsg.h.numAnswers == 1 ? "" : "s",
3861*4b22b933Srs200217 m->omsg.h.numAuthorities, m->omsg.h.numAuthorities == 1 ? "" : "s", intf->InterfaceID);
3862*4b22b933Srs200217 if (intf->IPv4Available) mDNSSendDNSMessage(m, &m->omsg, queryptr, intf->InterfaceID, &AllDNSLinkGroup_v4, MulticastDNSPort, -1, mDNSNULL);
3863*4b22b933Srs200217 if (intf->IPv6Available) mDNSSendDNSMessage(m, &m->omsg, queryptr, intf->InterfaceID, &AllDNSLinkGroup_v6, MulticastDNSPort, -1, mDNSNULL);
3864*4b22b933Srs200217 if (!m->SuppressSending) m->SuppressSending = NonZeroTime(m->timenow + (mDNSPlatformOneSecond+9)/10);
3865*4b22b933Srs200217 if (++pktcount >= 1000)
3866*4b22b933Srs200217 { LogMsg("SendQueries exceeded loop limit %d: giving up", pktcount); break; }
3867*4b22b933Srs200217 // There might be more records left in the known answer list, or more questions to send
3868*4b22b933Srs200217 // on this interface, so go around one more time and try again.
3869*4b22b933Srs200217 }
3870*4b22b933Srs200217 else // Nothing more to send on this interface; go to next
3871*4b22b933Srs200217 {
3872*4b22b933Srs200217 const NetworkInterfaceInfo *next = GetFirstActiveInterface(intf->next);
3873*4b22b933Srs200217 #if MDNS_DEBUGMSGS && 0
3874*4b22b933Srs200217 const char *const msg = next ? "SendQueries: Nothing more on %p; moving to %p" : "SendQueries: Nothing more on %p";
3875*4b22b933Srs200217 debugf(msg, intf, next);
3876*4b22b933Srs200217 #endif
3877*4b22b933Srs200217 intf = next;
3878*4b22b933Srs200217 }
3879*4b22b933Srs200217 }
3880*4b22b933Srs200217
3881*4b22b933Srs200217 // 4. Final housekeeping
3882*4b22b933Srs200217
3883*4b22b933Srs200217 // 4a. Debugging check: Make sure we announced all our records
3884*4b22b933Srs200217 for (ar = m->ResourceRecords; ar; ar=ar->next)
3885*4b22b933Srs200217 if (ar->SendRNow)
3886*4b22b933Srs200217 {
3887*4b22b933Srs200217 if (ar->resrec.InterfaceID != mDNSInterface_LocalOnly)
3888*4b22b933Srs200217 LogMsg("SendQueries: No active interface to send: %s", ARDisplayString(m, ar));
3889*4b22b933Srs200217 ar->SendRNow = mDNSNULL;
3890*4b22b933Srs200217 }
3891*4b22b933Srs200217
3892*4b22b933Srs200217 // 4b. When we have lingering cache records that we're keeping around for a few seconds in the hope
3893*4b22b933Srs200217 // that their interface which went away might come back again, the logic will want to send queries
3894*4b22b933Srs200217 // for those records, but we can't because their interface isn't here any more, so to keep the
3895*4b22b933Srs200217 // state machine ticking over we just pretend we did so.
3896*4b22b933Srs200217 // If the interface does not come back in time, the cache record will expire naturally
3897*4b22b933Srs200217 FORALL_CACHERECORDS(slot, cg, cr)
3898*4b22b933Srs200217 if (cr->CRActiveQuestion && cr->UnansweredQueries < MaxUnansweredQueries && m->timenow - cr->NextRequiredQuery >= 0)
3899*4b22b933Srs200217 {
3900*4b22b933Srs200217 cr->UnansweredQueries++;
3901*4b22b933Srs200217 cr->CRActiveQuestion->SendQNow = mDNSNULL;
3902*4b22b933Srs200217 SetNextCacheCheckTime(m, cr);
3903*4b22b933Srs200217 }
3904*4b22b933Srs200217
3905*4b22b933Srs200217 // 4c. Debugging check: Make sure we sent all our planned questions
3906*4b22b933Srs200217 // Do this AFTER the lingering cache records check above, because that will prevent spurious warnings for questions
3907*4b22b933Srs200217 // we legitimately couldn't send because the interface is no longer available
3908*4b22b933Srs200217 for (q = m->Questions; q; q=q->next)
3909*4b22b933Srs200217 if (q->SendQNow)
3910*4b22b933Srs200217 {
3911*4b22b933Srs200217 LogMsg("SendQueries: No active interface to send: %##s %s", q->qname.c, DNSTypeName(q->qtype));
3912*4b22b933Srs200217 q->SendQNow = mDNSNULL;
3913*4b22b933Srs200217 }
3914*4b22b933Srs200217 }
3915*4b22b933Srs200217
3916*4b22b933Srs200217 // ***************************************************************************
3917*4b22b933Srs200217 #if COMPILER_LIKES_PRAGMA_MARK
3918*4b22b933Srs200217 #pragma mark -
3919*4b22b933Srs200217 #pragma mark - RR List Management & Task Management
3920*4b22b933Srs200217 #endif
3921*4b22b933Srs200217
3922*4b22b933Srs200217 // NOTE: AnswerQuestionWithResourceRecord can call a user callback, which may change the record list and/or question list.
3923*4b22b933Srs200217 // Any code walking either list must use the CurrentQuestion and/or CurrentRecord mechanism to protect against this.
AnswerQuestionWithResourceRecord(mDNS * const m,DNSQuestion * q,CacheRecord * rr,mDNSBool AddRecord)3924*4b22b933Srs200217 mDNSlocal void AnswerQuestionWithResourceRecord(mDNS *const m, DNSQuestion *q, CacheRecord *rr, mDNSBool AddRecord)
3925*4b22b933Srs200217 {
3926*4b22b933Srs200217 verbosedebugf("AnswerQuestionWithResourceRecord:%4lu %s TTL%6lu %##s (%s)",
3927*4b22b933Srs200217 q->CurrentAnswers, AddRecord ? "Add" : "Rmv", rr->resrec.rroriginalttl, rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype));
3928*4b22b933Srs200217
3929*4b22b933Srs200217 // Note: Use caution here. In the case of records with rr->DelayDelivery set, AnswerQuestionWithResourceRecord(... mDNStrue)
3930*4b22b933Srs200217 // may be called twice, once when the record is received, and again when it's time to notify local clients.
3931*4b22b933Srs200217 // If any counters or similar are added here, care must be taken to ensure that they are not double-incremented by this.
3932*4b22b933Srs200217
3933*4b22b933Srs200217 rr->LastUsed = m->timenow;
3934*4b22b933Srs200217 if (ActiveQuestion(q) && rr->CRActiveQuestion != q)
3935*4b22b933Srs200217 {
3936*4b22b933Srs200217 if (!rr->CRActiveQuestion) m->rrcache_active++; // If not previously active, increment rrcache_active count
3937*4b22b933Srs200217 rr->CRActiveQuestion = q; // We know q is non-null
3938*4b22b933Srs200217 SetNextCacheCheckTime(m, rr);
3939*4b22b933Srs200217 }
3940*4b22b933Srs200217
3941*4b22b933Srs200217 // If this is:
3942*4b22b933Srs200217 // (a) a no-cache add, where we've already done at least one 'QM' query, or
3943*4b22b933Srs200217 // (b) a normal add, where we have at least one unique-type answer,
3944*4b22b933Srs200217 // then there's no need to keep polling the network.
3945*4b22b933Srs200217 // (If we have an answer in the cache, then we'll automatically ask again in time to stop it expiring.)
3946*4b22b933Srs200217 if ((AddRecord == 2 && !q->RequestUnicast) ||
3947*4b22b933Srs200217 (AddRecord == 1 && (q->ExpectUnique || (rr->resrec.RecordType & kDNSRecordTypePacketUniqueMask))))
3948*4b22b933Srs200217 if (ActiveQuestion(q))
3949*4b22b933Srs200217 {
3950*4b22b933Srs200217 q->LastQTime = m->timenow;
3951*4b22b933Srs200217 q->LastQTxTime = m->timenow;
3952*4b22b933Srs200217 q->RecentAnswerPkts = 0;
3953*4b22b933Srs200217 q->ThisQInterval = MaxQuestionInterval;
3954*4b22b933Srs200217 q->RequestUnicast = mDNSfalse;
3955*4b22b933Srs200217 }
3956*4b22b933Srs200217
3957*4b22b933Srs200217 if (rr->DelayDelivery) return; // We'll come back later when CacheRecordDeferredAdd() calls us
3958*4b22b933Srs200217
3959*4b22b933Srs200217 m->mDNS_reentrancy++; // Increment to allow client to legally make mDNS API calls from the callback
3960*4b22b933Srs200217 if (q->QuestionCallback)
3961*4b22b933Srs200217 q->QuestionCallback(m, q, &rr->resrec, AddRecord);
3962*4b22b933Srs200217 m->mDNS_reentrancy--; // Decrement to block mDNS API calls again
3963*4b22b933Srs200217 // CAUTION: MUST NOT do anything more with q after calling q->QuestionCallback(), because the client's callback function
3964*4b22b933Srs200217 // is allowed to do anything, including starting/stopping queries, registering/deregistering records, etc.
3965*4b22b933Srs200217 // Right now the only routines that call AnswerQuestionWithResourceRecord() are CacheRecordAdd(), CacheRecordRmv()
3966*4b22b933Srs200217 // and AnswerNewQuestion(), and all of them use the "m->CurrentQuestion" mechanism to protect against questions
3967*4b22b933Srs200217 // being deleted out from under them.
3968*4b22b933Srs200217 }
3969*4b22b933Srs200217
CacheRecordDeferredAdd(mDNS * const m,CacheRecord * rr)3970*4b22b933Srs200217 mDNSlocal void CacheRecordDeferredAdd(mDNS *const m, CacheRecord *rr)
3971*4b22b933Srs200217 {
3972*4b22b933Srs200217 rr->DelayDelivery = 0; // Note, only need to call SetNextCacheCheckTime() when DelayDelivery is set, not when it's cleared
3973*4b22b933Srs200217 if (m->CurrentQuestion) LogMsg("CacheRecordDeferredAdd ERROR m->CurrentQuestion already set");
3974*4b22b933Srs200217 m->CurrentQuestion = m->Questions;
3975*4b22b933Srs200217 while (m->CurrentQuestion && m->CurrentQuestion != m->NewQuestions)
3976*4b22b933Srs200217 {
3977*4b22b933Srs200217 DNSQuestion *q = m->CurrentQuestion;
3978*4b22b933Srs200217 m->CurrentQuestion = q->next;
3979*4b22b933Srs200217 if (ResourceRecordAnswersQuestion(&rr->resrec, q))
3980*4b22b933Srs200217 AnswerQuestionWithResourceRecord(m, q, rr, mDNStrue);
3981*4b22b933Srs200217 }
3982*4b22b933Srs200217 m->CurrentQuestion = mDNSNULL;
3983*4b22b933Srs200217 }
3984*4b22b933Srs200217
CheckForSoonToExpireRecords(mDNS * const m,const domainname * const name,const mDNSu32 namehash,const mDNSu32 slot)3985*4b22b933Srs200217 mDNSlocal mDNSs32 CheckForSoonToExpireRecords(mDNS *const m, const domainname *const name, const mDNSu32 namehash, const mDNSu32 slot)
3986*4b22b933Srs200217 {
3987*4b22b933Srs200217 const mDNSs32 threshhold = m->timenow + mDNSPlatformOneSecond; // See if there are any records expiring within one second
3988*4b22b933Srs200217 const mDNSs32 start = m->timenow - 0x10000000;
3989*4b22b933Srs200217 mDNSs32 delay = start;
3990*4b22b933Srs200217 CacheGroup *cg = CacheGroupForName(m, slot, namehash, name);
3991*4b22b933Srs200217 CacheRecord *rr;
3992*4b22b933Srs200217 for (rr = cg ? cg->members : mDNSNULL; rr; rr=rr->next)
3993*4b22b933Srs200217 if (rr->resrec.namehash == namehash && SameDomainName(rr->resrec.name, name))
3994*4b22b933Srs200217 if (threshhold - RRExpireTime(rr) >= 0) // If we have records about to expire within a second
3995*4b22b933Srs200217 if (delay - RRExpireTime(rr) < 0) // then delay until after they've been deleted
3996*4b22b933Srs200217 delay = RRExpireTime(rr);
3997*4b22b933Srs200217 if (delay - start > 0) return(NonZeroTime(delay));
3998*4b22b933Srs200217 else return(0);
3999*4b22b933Srs200217 }
4000*4b22b933Srs200217
4001*4b22b933Srs200217 // CacheRecordAdd is only called from mDNSCoreReceiveResponse, *never* directly as a result of a client API call.
4002*4b22b933Srs200217 // If new questions are created as a result of invoking client callbacks, they will be added to
4003*4b22b933Srs200217 // the end of the question list, and m->NewQuestions will be set to indicate the first new question.
4004*4b22b933Srs200217 // rr is a new CacheRecord just received into our cache
4005*4b22b933Srs200217 // (kDNSRecordTypePacketAns/PacketAnsUnique/PacketAdd/PacketAddUnique).
4006*4b22b933Srs200217 // NOTE: CacheRecordAdd calls AnswerQuestionWithResourceRecord which can call a user callback,
4007*4b22b933Srs200217 // which may change the record list and/or question list.
4008*4b22b933Srs200217 // Any code walking either list must use the CurrentQuestion and/or CurrentRecord mechanism to protect against this.
CacheRecordAdd(mDNS * const m,CacheRecord * rr)4009*4b22b933Srs200217 mDNSlocal void CacheRecordAdd(mDNS *const m, CacheRecord *rr)
4010*4b22b933Srs200217 {
4011*4b22b933Srs200217 if (m->CurrentQuestion) LogMsg("CacheRecordAdd ERROR m->CurrentQuestion already set");
4012*4b22b933Srs200217 m->CurrentQuestion = m->Questions;
4013*4b22b933Srs200217 while (m->CurrentQuestion && m->CurrentQuestion != m->NewQuestions)
4014*4b22b933Srs200217 {
4015*4b22b933Srs200217 DNSQuestion *q = m->CurrentQuestion;
4016*4b22b933Srs200217 m->CurrentQuestion = q->next;
4017*4b22b933Srs200217 if (ResourceRecordAnswersQuestion(&rr->resrec, q))
4018*4b22b933Srs200217 {
4019*4b22b933Srs200217 // If this question is one that's actively sending queries, and it's received ten answers within one
4020*4b22b933Srs200217 // second of sending the last query packet, then that indicates some radical network topology change,
4021*4b22b933Srs200217 // so reset its exponential backoff back to the start. We must be at least at the eight-second interval
4022*4b22b933Srs200217 // to do this. If we're at the four-second interval, or less, there's not much benefit accelerating
4023*4b22b933Srs200217 // because we will anyway send another query within a few seconds. The first reset query is sent out
4024*4b22b933Srs200217 // randomized over the next four seconds to reduce possible synchronization between machines.
4025*4b22b933Srs200217 if (q->LastAnswerPktNum != m->PktNum)
4026*4b22b933Srs200217 {
4027*4b22b933Srs200217 q->LastAnswerPktNum = m->PktNum;
4028*4b22b933Srs200217 if (ActiveQuestion(q) && ++q->RecentAnswerPkts >= 10 &&
4029*4b22b933Srs200217 q->ThisQInterval > InitialQuestionInterval*32 && m->timenow - q->LastQTxTime < mDNSPlatformOneSecond)
4030*4b22b933Srs200217 {
4031*4b22b933Srs200217 LogMsg("CacheRecordAdd: %##s (%s) got immediate answer burst; restarting exponential backoff sequence",
4032*4b22b933Srs200217 q->qname.c, DNSTypeName(q->qtype));
4033*4b22b933Srs200217 q->LastQTime = m->timenow - InitialQuestionInterval + (mDNSs32)mDNSRandom((mDNSu32)mDNSPlatformOneSecond*4);
4034*4b22b933Srs200217 q->ThisQInterval = InitialQuestionInterval;
4035*4b22b933Srs200217 SetNextQueryTime(m,q);
4036*4b22b933Srs200217 }
4037*4b22b933Srs200217 }
4038*4b22b933Srs200217 verbosedebugf("CacheRecordAdd %p %##s (%s) %lu",
4039*4b22b933Srs200217 rr, rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype), rr->resrec.rroriginalttl);
4040*4b22b933Srs200217 q->CurrentAnswers++;
4041*4b22b933Srs200217 if (rr->resrec.rdlength > SmallRecordLimit) q->LargeAnswers++;
4042*4b22b933Srs200217 if (rr->resrec.RecordType & kDNSRecordTypePacketUniqueMask) q->UniqueAnswers++;
4043*4b22b933Srs200217 if (q->CurrentAnswers > 4000)
4044*4b22b933Srs200217 {
4045*4b22b933Srs200217 static int msgcount = 0;
4046*4b22b933Srs200217 if (msgcount++ < 10)
4047*4b22b933Srs200217 LogMsg("CacheRecordAdd: %##s (%s) has %d answers; shedding records to resist DOS attack",
4048*4b22b933Srs200217 q->qname.c, DNSTypeName(q->qtype), q->CurrentAnswers);
4049*4b22b933Srs200217 rr->resrec.rroriginalttl = 1;
4050*4b22b933Srs200217 rr->UnansweredQueries = MaxUnansweredQueries;
4051*4b22b933Srs200217 }
4052*4b22b933Srs200217 AnswerQuestionWithResourceRecord(m, q, rr, mDNStrue);
4053*4b22b933Srs200217 // MUST NOT dereference q again after calling AnswerQuestionWithResourceRecord()
4054*4b22b933Srs200217 }
4055*4b22b933Srs200217 }
4056*4b22b933Srs200217 m->CurrentQuestion = mDNSNULL;
4057*4b22b933Srs200217 SetNextCacheCheckTime(m, rr);
4058*4b22b933Srs200217 }
4059*4b22b933Srs200217
4060*4b22b933Srs200217 // NoCacheAnswer is only called from mDNSCoreReceiveResponse, *never* directly as a result of a client API call.
4061*4b22b933Srs200217 // If new questions are created as a result of invoking client callbacks, they will be added to
4062*4b22b933Srs200217 // the end of the question list, and m->NewQuestions will be set to indicate the first new question.
4063*4b22b933Srs200217 // rr is a new CacheRecord just received from the wire (kDNSRecordTypePacketAns/AnsUnique/Add/AddUnique)
4064*4b22b933Srs200217 // but we don't have any place to cache it. We'll deliver question 'add' events now, but we won't have any
4065*4b22b933Srs200217 // way to deliver 'remove' events in future, nor will we be able to include this in known-answer lists,
4066*4b22b933Srs200217 // so we immediately bump ThisQInterval up to MaxQuestionInterval to avoid pounding the network.
4067*4b22b933Srs200217 // NOTE: NoCacheAnswer calls AnswerQuestionWithResourceRecord which can call a user callback,
4068*4b22b933Srs200217 // which may change the record list and/or question list.
4069*4b22b933Srs200217 // Any code walking either list must use the CurrentQuestion and/or CurrentRecord mechanism to protect against this.
NoCacheAnswer(mDNS * const m,CacheRecord * rr)4070*4b22b933Srs200217 mDNSlocal void NoCacheAnswer(mDNS *const m, CacheRecord *rr)
4071*4b22b933Srs200217 {
4072*4b22b933Srs200217 LogMsg("No cache space: Delivering non-cached result for %##s", m->rec.r.resrec.name->c);
4073*4b22b933Srs200217 if (m->CurrentQuestion) LogMsg("NoCacheAnswer ERROR m->CurrentQuestion already set");
4074*4b22b933Srs200217 m->CurrentQuestion = m->Questions;
4075*4b22b933Srs200217 while (m->CurrentQuestion)
4076*4b22b933Srs200217 {
4077*4b22b933Srs200217 DNSQuestion *q = m->CurrentQuestion;
4078*4b22b933Srs200217 m->CurrentQuestion = q->next;
4079*4b22b933Srs200217 if (ResourceRecordAnswersQuestion(&rr->resrec, q))
4080*4b22b933Srs200217 AnswerQuestionWithResourceRecord(m, q, rr, 2); // Value '2' indicates "don't expect 'remove' events for this"
4081*4b22b933Srs200217 // MUST NOT dereference q again after calling AnswerQuestionWithResourceRecord()
4082*4b22b933Srs200217 }
4083*4b22b933Srs200217 m->CurrentQuestion = mDNSNULL;
4084*4b22b933Srs200217 }
4085*4b22b933Srs200217
4086*4b22b933Srs200217 // CacheRecordRmv is only called from CheckCacheExpiration, which is called from mDNS_Execute
4087*4b22b933Srs200217 // If new questions are created as a result of invoking client callbacks, they will be added to
4088*4b22b933Srs200217 // the end of the question list, and m->NewQuestions will be set to indicate the first new question.
4089*4b22b933Srs200217 // rr is an existing cache CacheRecord that just expired and is being deleted
4090*4b22b933Srs200217 // (kDNSRecordTypePacketAns/PacketAnsUnique/PacketAdd/PacketAddUnique).
4091*4b22b933Srs200217 // NOTE: CacheRecordRmv calls AnswerQuestionWithResourceRecord which can call a user callback,
4092*4b22b933Srs200217 // which may change the record list and/or question list.
4093*4b22b933Srs200217 // Any code walking either list must use the CurrentQuestion and/or CurrentRecord mechanism to protect against this.
CacheRecordRmv(mDNS * const m,CacheRecord * rr)4094*4b22b933Srs200217 mDNSlocal void CacheRecordRmv(mDNS *const m, CacheRecord *rr)
4095*4b22b933Srs200217 {
4096*4b22b933Srs200217 if (m->CurrentQuestion) LogMsg("CacheRecordRmv ERROR m->CurrentQuestion already set");
4097*4b22b933Srs200217 m->CurrentQuestion = m->Questions;
4098*4b22b933Srs200217 while (m->CurrentQuestion && m->CurrentQuestion != m->NewQuestions)
4099*4b22b933Srs200217 {
4100*4b22b933Srs200217 DNSQuestion *q = m->CurrentQuestion;
4101*4b22b933Srs200217 m->CurrentQuestion = q->next;
4102*4b22b933Srs200217 if (ResourceRecordAnswersQuestion(&rr->resrec, q))
4103*4b22b933Srs200217 {
4104*4b22b933Srs200217 verbosedebugf("CacheRecordRmv %p %s", rr, CRDisplayString(m, rr));
4105*4b22b933Srs200217 if (q->CurrentAnswers == 0)
4106*4b22b933Srs200217 LogMsg("CacheRecordRmv ERROR: How can CurrentAnswers already be zero for %p %##s (%s)?",
4107*4b22b933Srs200217 q, q->qname.c, DNSTypeName(q->qtype));
4108*4b22b933Srs200217 else
4109*4b22b933Srs200217 {
4110*4b22b933Srs200217 q->CurrentAnswers--;
4111*4b22b933Srs200217 if (rr->resrec.rdlength > SmallRecordLimit) q->LargeAnswers--;
4112*4b22b933Srs200217 if (rr->resrec.RecordType & kDNSRecordTypePacketUniqueMask) q->UniqueAnswers--;
4113*4b22b933Srs200217 }
4114*4b22b933Srs200217 if (q->CurrentAnswers == 0)
4115*4b22b933Srs200217 {
4116*4b22b933Srs200217 debugf("CacheRecordRmv: Zero current answers for %##s (%s); will reconfirm antecedents",
4117*4b22b933Srs200217 q->qname.c, DNSTypeName(q->qtype));
4118*4b22b933Srs200217 ReconfirmAntecedents(m, q);
4119*4b22b933Srs200217 }
4120*4b22b933Srs200217 q->FlappingInterface = mDNSNULL;
4121*4b22b933Srs200217 AnswerQuestionWithResourceRecord(m, q, rr, mDNSfalse);
4122*4b22b933Srs200217 // MUST NOT dereference q again after calling AnswerQuestionWithResourceRecord()
4123*4b22b933Srs200217 }
4124*4b22b933Srs200217 }
4125*4b22b933Srs200217 m->CurrentQuestion = mDNSNULL;
4126*4b22b933Srs200217 }
4127*4b22b933Srs200217
ReleaseCacheEntity(mDNS * const m,CacheEntity * e)4128*4b22b933Srs200217 mDNSlocal void ReleaseCacheEntity(mDNS *const m, CacheEntity *e)
4129*4b22b933Srs200217 {
4130*4b22b933Srs200217 #if MACOSX_MDNS_MALLOC_DEBUGGING >= 1
4131*4b22b933Srs200217 unsigned int i;
4132*4b22b933Srs200217 for (i=0; i<sizeof(*e); i++) ((char*)e)[i] = 0xFF;
4133*4b22b933Srs200217 #endif
4134*4b22b933Srs200217 e->next = m->rrcache_free;
4135*4b22b933Srs200217 m->rrcache_free = e;
4136*4b22b933Srs200217 m->rrcache_totalused--;
4137*4b22b933Srs200217 }
4138*4b22b933Srs200217
ReleaseCacheGroup(mDNS * const m,CacheGroup ** cp)4139*4b22b933Srs200217 mDNSlocal void ReleaseCacheGroup(mDNS *const m, CacheGroup **cp)
4140*4b22b933Srs200217 {
4141*4b22b933Srs200217 CacheEntity *e = (CacheEntity *)(*cp);
4142*4b22b933Srs200217 //LogMsg("ReleaseCacheGroup: Releasing CacheGroup for %p, %##s", (*cp)->name->c, (*cp)->name->c);
4143*4b22b933Srs200217 if ((*cp)->rrcache_tail != &(*cp)->members)
4144*4b22b933Srs200217 LogMsg("ERROR: (*cp)->members == mDNSNULL but (*cp)->rrcache_tail != &(*cp)->members)");
4145*4b22b933Srs200217 //if ((*cp)->name != (domainname*)((*cp)->namestorage))
4146*4b22b933Srs200217 // LogMsg("ReleaseCacheGroup: %##s, %p %p", (*cp)->name->c, (*cp)->name, (domainname*)((*cp)->namestorage));
4147*4b22b933Srs200217 if ((*cp)->name != (domainname*)((*cp)->namestorage)) mDNSPlatformMemFree((*cp)->name);
4148*4b22b933Srs200217 (*cp)->name = mDNSNULL;
4149*4b22b933Srs200217 *cp = (*cp)->next; // Cut record from list
4150*4b22b933Srs200217 ReleaseCacheEntity(m, e);
4151*4b22b933Srs200217 }
4152*4b22b933Srs200217
ReleaseCacheRecord(mDNS * const m,CacheRecord * r)4153*4b22b933Srs200217 mDNSlocal void ReleaseCacheRecord(mDNS *const m, CacheRecord *r)
4154*4b22b933Srs200217 {
4155*4b22b933Srs200217 if (r->resrec.rdata && r->resrec.rdata != (RData*)&r->rdatastorage) mDNSPlatformMemFree(r->resrec.rdata);
4156*4b22b933Srs200217 r->resrec.rdata = mDNSNULL;
4157*4b22b933Srs200217 ReleaseCacheEntity(m, (CacheEntity *)r);
4158*4b22b933Srs200217 }
4159*4b22b933Srs200217
4160*4b22b933Srs200217 // Note: We want to be careful that we deliver all the CacheRecordRmv calls before delivering
4161*4b22b933Srs200217 // CacheRecordDeferredAdd calls. The in-order nature of the cache lists ensures that all
4162*4b22b933Srs200217 // callbacks for old records are delivered before callbacks for newer records.
CheckCacheExpiration(mDNS * const m,CacheGroup * cg)4163*4b22b933Srs200217 mDNSlocal void CheckCacheExpiration(mDNS *const m, CacheGroup *cg)
4164*4b22b933Srs200217 {
4165*4b22b933Srs200217 CacheRecord **rp = &cg->members;
4166*4b22b933Srs200217
4167*4b22b933Srs200217 if (m->lock_rrcache) { LogMsg("CheckCacheExpiration ERROR! Cache already locked!"); return; }
4168*4b22b933Srs200217 m->lock_rrcache = 1;
4169*4b22b933Srs200217
4170*4b22b933Srs200217 while (*rp)
4171*4b22b933Srs200217 {
4172*4b22b933Srs200217 CacheRecord *const rr = *rp;
4173*4b22b933Srs200217 mDNSs32 event = RRExpireTime(rr);
4174*4b22b933Srs200217 if (m->timenow - event >= 0) // If expired, delete it
4175*4b22b933Srs200217 {
4176*4b22b933Srs200217 *rp = rr->next; // Cut it from the list
4177*4b22b933Srs200217 verbosedebugf("CheckCacheExpiration: Deleting %s", CRDisplayString(m, rr));
4178*4b22b933Srs200217 if (rr->CRActiveQuestion) // If this record has one or more active questions, tell them it's going away
4179*4b22b933Srs200217 {
4180*4b22b933Srs200217 CacheRecordRmv(m, rr);
4181*4b22b933Srs200217 m->rrcache_active--;
4182*4b22b933Srs200217 }
4183*4b22b933Srs200217 ReleaseCacheRecord(m, rr);
4184*4b22b933Srs200217 }
4185*4b22b933Srs200217 else // else, not expired; see if we need to query
4186*4b22b933Srs200217 {
4187*4b22b933Srs200217 if (rr->DelayDelivery && rr->DelayDelivery - m->timenow > 0)
4188*4b22b933Srs200217 event = rr->DelayDelivery;
4189*4b22b933Srs200217 else
4190*4b22b933Srs200217 {
4191*4b22b933Srs200217 if (rr->DelayDelivery) CacheRecordDeferredAdd(m, rr);
4192*4b22b933Srs200217 if (rr->CRActiveQuestion && rr->UnansweredQueries < MaxUnansweredQueries)
4193*4b22b933Srs200217 {
4194*4b22b933Srs200217 if (m->timenow - rr->NextRequiredQuery < 0) // If not yet time for next query
4195*4b22b933Srs200217 event = rr->NextRequiredQuery; // then just record when we want the next query
4196*4b22b933Srs200217 else // else trigger our question to go out now
4197*4b22b933Srs200217 {
4198*4b22b933Srs200217 // Set NextScheduledQuery to timenow so that SendQueries() will run.
4199*4b22b933Srs200217 // SendQueries() will see that we have records close to expiration, and send FEQs for them.
4200*4b22b933Srs200217 m->NextScheduledQuery = m->timenow;
4201*4b22b933Srs200217 // After sending the query we'll increment UnansweredQueries and call SetNextCacheCheckTime(),
4202*4b22b933Srs200217 // which will correctly update m->NextCacheCheck for us.
4203*4b22b933Srs200217 event = m->timenow + 0x3FFFFFFF;
4204*4b22b933Srs200217 }
4205*4b22b933Srs200217 }
4206*4b22b933Srs200217 }
4207*4b22b933Srs200217 verbosedebugf("CheckCacheExpiration:%6d %5d %s",
4208*4b22b933Srs200217 (event-m->timenow) / mDNSPlatformOneSecond, CacheCheckGracePeriod(rr), CRDisplayString(m, rr));
4209*4b22b933Srs200217 if (m->NextCacheCheck - (event + CacheCheckGracePeriod(rr)) > 0)
4210*4b22b933Srs200217 m->NextCacheCheck = (event + CacheCheckGracePeriod(rr));
4211*4b22b933Srs200217 rp = &rr->next;
4212*4b22b933Srs200217 }
4213*4b22b933Srs200217 }
4214*4b22b933Srs200217 if (cg->rrcache_tail != rp) verbosedebugf("CheckCacheExpiration: Updating CacheGroup tail from %p to %p", cg->rrcache_tail, rp);
4215*4b22b933Srs200217 cg->rrcache_tail = rp;
4216*4b22b933Srs200217 m->lock_rrcache = 0;
4217*4b22b933Srs200217 }
4218*4b22b933Srs200217
AnswerNewQuestion(mDNS * const m)4219*4b22b933Srs200217 mDNSlocal void AnswerNewQuestion(mDNS *const m)
4220*4b22b933Srs200217 {
4221*4b22b933Srs200217 mDNSBool ShouldQueryImmediately = mDNStrue;
4222*4b22b933Srs200217 CacheRecord *rr;
4223*4b22b933Srs200217 DNSQuestion *q = m->NewQuestions; // Grab the question we're going to answer
4224*4b22b933Srs200217 const mDNSu32 slot = HashSlot(&q->qname);
4225*4b22b933Srs200217 CacheGroup *cg = CacheGroupForName(m, slot, q->qnamehash, &q->qname);
4226*4b22b933Srs200217
4227*4b22b933Srs200217 verbosedebugf("AnswerNewQuestion: Answering %##s (%s)", q->qname.c, DNSTypeName(q->qtype));
4228*4b22b933Srs200217
4229*4b22b933Srs200217 if (cg) CheckCacheExpiration(m, cg);
4230*4b22b933Srs200217 m->NewQuestions = q->next; // Advance NewQuestions to the next *after* calling CheckCacheExpiration();
4231*4b22b933Srs200217
4232*4b22b933Srs200217 if (m->lock_rrcache) LogMsg("AnswerNewQuestion ERROR! Cache already locked!");
4233*4b22b933Srs200217 // This should be safe, because calling the client's question callback may cause the
4234*4b22b933Srs200217 // question list to be modified, but should not ever cause the rrcache list to be modified.
4235*4b22b933Srs200217 // If the client's question callback deletes the question, then m->CurrentQuestion will
4236*4b22b933Srs200217 // be advanced, and we'll exit out of the loop
4237*4b22b933Srs200217 m->lock_rrcache = 1;
4238*4b22b933Srs200217 if (m->CurrentQuestion) LogMsg("AnswerNewQuestion ERROR m->CurrentQuestion already set");
4239*4b22b933Srs200217 m->CurrentQuestion = q; // Indicate which question we're answering, so we'll know if it gets deleted
4240*4b22b933Srs200217
4241*4b22b933Srs200217 if (q->InterfaceID == mDNSInterface_Any) // If 'mDNSInterface_Any' question, see if we want to tell it about LocalOnly records
4242*4b22b933Srs200217 {
4243*4b22b933Srs200217 if (m->CurrentRecord) LogMsg("AnswerNewLocalOnlyQuestion ERROR m->CurrentRecord already set");
4244*4b22b933Srs200217 m->CurrentRecord = m->ResourceRecords;
4245*4b22b933Srs200217 while (m->CurrentRecord && m->CurrentRecord != m->NewLocalRecords)
4246*4b22b933Srs200217 {
4247*4b22b933Srs200217 AuthRecord *rr = m->CurrentRecord;
4248*4b22b933Srs200217 m->CurrentRecord = rr->next;
4249*4b22b933Srs200217 if (rr->resrec.InterfaceID == mDNSInterface_LocalOnly)
4250*4b22b933Srs200217 if (ResourceRecordAnswersQuestion(&rr->resrec, q))
4251*4b22b933Srs200217 {
4252*4b22b933Srs200217 AnswerLocalOnlyQuestionWithResourceRecord(m, q, rr, mDNStrue);
4253*4b22b933Srs200217 // MUST NOT dereference q again after calling AnswerLocalOnlyQuestionWithResourceRecord()
4254*4b22b933Srs200217 if (m->CurrentQuestion != q) break; // If callback deleted q, then we're finished here
4255*4b22b933Srs200217 }
4256*4b22b933Srs200217 }
4257*4b22b933Srs200217 m->CurrentRecord = mDNSNULL;
4258*4b22b933Srs200217 }
4259*4b22b933Srs200217
4260*4b22b933Srs200217 for (rr = cg ? cg->members : mDNSNULL; rr; rr=rr->next)
4261*4b22b933Srs200217 if (ResourceRecordAnswersQuestion(&rr->resrec, q))
4262*4b22b933Srs200217 {
4263*4b22b933Srs200217 // SecsSinceRcvd is whole number of elapsed seconds, rounded down
4264*4b22b933Srs200217 mDNSu32 SecsSinceRcvd = ((mDNSu32)(m->timenow - rr->TimeRcvd)) / mDNSPlatformOneSecond;
4265*4b22b933Srs200217 if (rr->resrec.rroriginalttl <= SecsSinceRcvd)
4266*4b22b933Srs200217 {
4267*4b22b933Srs200217 LogMsg("AnswerNewQuestion: How is rr->resrec.rroriginalttl %lu <= SecsSinceRcvd %lu for %##s (%s)",
4268*4b22b933Srs200217 rr->resrec.rroriginalttl, SecsSinceRcvd, rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype));
4269*4b22b933Srs200217 continue; // Go to next one in loop
4270*4b22b933Srs200217 }
4271*4b22b933Srs200217
4272*4b22b933Srs200217 // If this record set is marked unique, then that means we can reasonably assume we have the whole set
4273*4b22b933Srs200217 // -- we don't need to rush out on the network and query immediately to see if there are more answers out there
4274*4b22b933Srs200217 if ((rr->resrec.RecordType & kDNSRecordTypePacketUniqueMask) || (q->ExpectUnique))
4275*4b22b933Srs200217 ShouldQueryImmediately = mDNSfalse;
4276*4b22b933Srs200217 q->CurrentAnswers++;
4277*4b22b933Srs200217 if (rr->resrec.rdlength > SmallRecordLimit) q->LargeAnswers++;
4278*4b22b933Srs200217 if (rr->resrec.RecordType & kDNSRecordTypePacketUniqueMask) q->UniqueAnswers++;
4279*4b22b933Srs200217 AnswerQuestionWithResourceRecord(m, q, rr, mDNStrue);
4280*4b22b933Srs200217 // MUST NOT dereference q again after calling AnswerQuestionWithResourceRecord()
4281*4b22b933Srs200217 if (m->CurrentQuestion != q) break; // If callback deleted q, then we're finished here
4282*4b22b933Srs200217 }
4283*4b22b933Srs200217 else if (RRTypeIsAddressType(rr->resrec.rrtype) && RRTypeIsAddressType(q->qtype))
4284*4b22b933Srs200217 if (rr->resrec.namehash == q->qnamehash && SameDomainName(rr->resrec.name, &q->qname))
4285*4b22b933Srs200217 ShouldQueryImmediately = mDNSfalse;
4286*4b22b933Srs200217
4287*4b22b933Srs200217 if (ShouldQueryImmediately && m->CurrentQuestion == q)
4288*4b22b933Srs200217 {
4289*4b22b933Srs200217 q->ThisQInterval = InitialQuestionInterval;
4290*4b22b933Srs200217 q->LastQTime = m->timenow - q->ThisQInterval;
4291*4b22b933Srs200217 m->NextScheduledQuery = m->timenow;
4292*4b22b933Srs200217 }
4293*4b22b933Srs200217 m->CurrentQuestion = mDNSNULL;
4294*4b22b933Srs200217 m->lock_rrcache = 0;
4295*4b22b933Srs200217 }
4296*4b22b933Srs200217
4297*4b22b933Srs200217 // When a NewLocalOnlyQuestion is created, AnswerNewLocalOnlyQuestion runs though our ResourceRecords delivering any
4298*4b22b933Srs200217 // appropriate answers, stopping if it reaches a NewLocalRecord -- these will be handled by AnswerLocalQuestions
AnswerNewLocalOnlyQuestion(mDNS * const m)4299*4b22b933Srs200217 mDNSlocal void AnswerNewLocalOnlyQuestion(mDNS *const m)
4300*4b22b933Srs200217 {
4301*4b22b933Srs200217 DNSQuestion *q = m->NewLocalOnlyQuestions; // Grab the question we're going to answer
4302*4b22b933Srs200217 m->NewLocalOnlyQuestions = q->next; // Advance NewQuestions to the next (if any)
4303*4b22b933Srs200217
4304*4b22b933Srs200217 debugf("AnswerNewLocalOnlyQuestion: Answering %##s (%s)", q->qname.c, DNSTypeName(q->qtype));
4305*4b22b933Srs200217
4306*4b22b933Srs200217 if (m->CurrentQuestion) LogMsg("AnswerNewLocalOnlyQuestion ERROR m->CurrentQuestion already set");
4307*4b22b933Srs200217 m->CurrentQuestion = q; // Indicate which question we're answering, so we'll know if it gets deleted
4308*4b22b933Srs200217
4309*4b22b933Srs200217 if (m->CurrentRecord) LogMsg("AnswerNewLocalOnlyQuestion ERROR m->CurrentRecord already set");
4310*4b22b933Srs200217 m->CurrentRecord = m->ResourceRecords;
4311*4b22b933Srs200217 while (m->CurrentRecord && m->CurrentRecord != m->NewLocalRecords)
4312*4b22b933Srs200217 {
4313*4b22b933Srs200217 AuthRecord *rr = m->CurrentRecord;
4314*4b22b933Srs200217 m->CurrentRecord = rr->next;
4315*4b22b933Srs200217 if (ResourceRecordAnswersQuestion(&rr->resrec, q))
4316*4b22b933Srs200217 {
4317*4b22b933Srs200217 AnswerLocalOnlyQuestionWithResourceRecord(m, q, rr, mDNStrue);
4318*4b22b933Srs200217 // MUST NOT dereference q again after calling AnswerLocalOnlyQuestionWithResourceRecord()
4319*4b22b933Srs200217 if (m->CurrentQuestion != q) break; // If callback deleted q, then we're finished here
4320*4b22b933Srs200217 }
4321*4b22b933Srs200217 }
4322*4b22b933Srs200217
4323*4b22b933Srs200217 m->CurrentQuestion = mDNSNULL;
4324*4b22b933Srs200217 m->CurrentRecord = mDNSNULL;
4325*4b22b933Srs200217 }
4326*4b22b933Srs200217
GetCacheEntity(mDNS * const m,const CacheGroup * const PreserveCG)4327*4b22b933Srs200217 mDNSlocal CacheEntity *GetCacheEntity(mDNS *const m, const CacheGroup *const PreserveCG)
4328*4b22b933Srs200217 {
4329*4b22b933Srs200217 CacheEntity *e = mDNSNULL;
4330*4b22b933Srs200217
4331*4b22b933Srs200217 if (m->lock_rrcache) { LogMsg("GetFreeCacheRR ERROR! Cache already locked!"); return(mDNSNULL); }
4332*4b22b933Srs200217 m->lock_rrcache = 1;
4333*4b22b933Srs200217
4334*4b22b933Srs200217 // If we have no free records, ask the client layer to give us some more memory
4335*4b22b933Srs200217 if (!m->rrcache_free && m->MainCallback)
4336*4b22b933Srs200217 {
4337*4b22b933Srs200217 if (m->rrcache_totalused != m->rrcache_size)
4338*4b22b933Srs200217 LogMsg("GetFreeCacheRR: count mismatch: m->rrcache_totalused %lu != m->rrcache_size %lu",
4339*4b22b933Srs200217 m->rrcache_totalused, m->rrcache_size);
4340*4b22b933Srs200217
4341*4b22b933Srs200217 // We don't want to be vulnerable to a malicious attacker flooding us with an infinite
4342*4b22b933Srs200217 // number of bogus records so that we keep growing our cache until the machine runs out of memory.
4343*4b22b933Srs200217 // To guard against this, if we're actively using less than 1/32 of our cache, then we
4344*4b22b933Srs200217 // purge all the unused records and recycle them, instead of allocating more memory.
4345*4b22b933Srs200217 if (m->rrcache_size >= 512 && m->rrcache_size / 32 > m->rrcache_active)
4346*4b22b933Srs200217 debugf("Possible denial-of-service attack in progress: m->rrcache_size %lu; m->rrcache_active %lu",
4347*4b22b933Srs200217 m->rrcache_size, m->rrcache_active);
4348*4b22b933Srs200217 else
4349*4b22b933Srs200217 {
4350*4b22b933Srs200217 m->mDNS_reentrancy++; // Increment to allow client to legally make mDNS API calls from the callback
4351*4b22b933Srs200217 m->MainCallback(m, mStatus_GrowCache);
4352*4b22b933Srs200217 m->mDNS_reentrancy--; // Decrement to block mDNS API calls again
4353*4b22b933Srs200217 }
4354*4b22b933Srs200217 }
4355*4b22b933Srs200217
4356*4b22b933Srs200217 // If we still have no free records, recycle all the records we can.
4357*4b22b933Srs200217 // Enumerating the entire cache is moderately expensive, so when we do it, we reclaim all the records we can in one pass.
4358*4b22b933Srs200217 if (!m->rrcache_free)
4359*4b22b933Srs200217 {
4360*4b22b933Srs200217 #if MDNS_DEBUGMSGS
4361*4b22b933Srs200217 mDNSu32 oldtotalused = m->rrcache_totalused;
4362*4b22b933Srs200217 #endif
4363*4b22b933Srs200217 mDNSu32 slot;
4364*4b22b933Srs200217 for (slot = 0; slot < CACHE_HASH_SLOTS; slot++)
4365*4b22b933Srs200217 {
4366*4b22b933Srs200217 CacheGroup **cp = &m->rrcache_hash[slot];
4367*4b22b933Srs200217 while (*cp)
4368*4b22b933Srs200217 {
4369*4b22b933Srs200217 CacheRecord **rp = &(*cp)->members;
4370*4b22b933Srs200217 while (*rp)
4371*4b22b933Srs200217 {
4372*4b22b933Srs200217 // Records that answer still-active questions are not candidates for recycling
4373*4b22b933Srs200217 // Records that are currently linked into the CacheFlushRecords list may not be recycled, or we'll crash
4374*4b22b933Srs200217 if ((*rp)->CRActiveQuestion || (*rp)->NextInCFList)
4375*4b22b933Srs200217 rp=&(*rp)->next;
4376*4b22b933Srs200217 else
4377*4b22b933Srs200217 {
4378*4b22b933Srs200217 CacheRecord *rr = *rp;
4379*4b22b933Srs200217 *rp = (*rp)->next; // Cut record from list
4380*4b22b933Srs200217 ReleaseCacheRecord(m, rr);
4381*4b22b933Srs200217 }
4382*4b22b933Srs200217 }
4383*4b22b933Srs200217 if ((*cp)->rrcache_tail != rp)
4384*4b22b933Srs200217 verbosedebugf("GetFreeCacheRR: Updating rrcache_tail[%lu] from %p to %p", slot, (*cp)->rrcache_tail, rp);
4385*4b22b933Srs200217 (*cp)->rrcache_tail = rp;
4386*4b22b933Srs200217 if ((*cp)->members || (*cp)==PreserveCG) cp=&(*cp)->next;
4387*4b22b933Srs200217 else ReleaseCacheGroup(m, cp);
4388*4b22b933Srs200217 }
4389*4b22b933Srs200217 }
4390*4b22b933Srs200217 #if MDNS_DEBUGMSGS
4391*4b22b933Srs200217 debugf("Clear unused records; m->rrcache_totalused was %lu; now %lu", oldtotalused, m->rrcache_totalused);
4392*4b22b933Srs200217 #endif
4393*4b22b933Srs200217 }
4394*4b22b933Srs200217
4395*4b22b933Srs200217 if (m->rrcache_free) // If there are records in the free list, take one
4396*4b22b933Srs200217 {
4397*4b22b933Srs200217 e = m->rrcache_free;
4398*4b22b933Srs200217 m->rrcache_free = e->next;
4399*4b22b933Srs200217 if (++m->rrcache_totalused >= m->rrcache_report)
4400*4b22b933Srs200217 {
4401*4b22b933Srs200217 debugf("RR Cache now using %ld objects", m->rrcache_totalused);
4402*4b22b933Srs200217 if (m->rrcache_report < 100) m->rrcache_report += 10;
4403*4b22b933Srs200217 else m->rrcache_report += 100;
4404*4b22b933Srs200217 }
4405*4b22b933Srs200217 mDNSPlatformMemZero(e, sizeof(*e));
4406*4b22b933Srs200217 }
4407*4b22b933Srs200217
4408*4b22b933Srs200217 m->lock_rrcache = 0;
4409*4b22b933Srs200217
4410*4b22b933Srs200217 return(e);
4411*4b22b933Srs200217 }
4412*4b22b933Srs200217
GetCacheRecord(mDNS * const m,CacheGroup * cg,mDNSu16 RDLength)4413*4b22b933Srs200217 mDNSlocal CacheRecord *GetCacheRecord(mDNS *const m, CacheGroup *cg, mDNSu16 RDLength)
4414*4b22b933Srs200217 {
4415*4b22b933Srs200217 CacheRecord *r = (CacheRecord *)GetCacheEntity(m, cg);
4416*4b22b933Srs200217 if (r)
4417*4b22b933Srs200217 {
4418*4b22b933Srs200217 r->resrec.rdata = (RData*)&r->rdatastorage; // By default, assume we're usually going to be using local storage
4419*4b22b933Srs200217 if (RDLength > InlineCacheRDSize) // If RDLength is too big, allocate extra storage
4420*4b22b933Srs200217 {
4421*4b22b933Srs200217 r->resrec.rdata = (RData*)mDNSPlatformMemAllocate(sizeofRDataHeader + RDLength);
4422*4b22b933Srs200217 if (r->resrec.rdata) r->resrec.rdata->MaxRDLength = r->resrec.rdlength = RDLength;
4423*4b22b933Srs200217 else { ReleaseCacheEntity(m, (CacheEntity*)r); r = mDNSNULL; }
4424*4b22b933Srs200217 }
4425*4b22b933Srs200217 }
4426*4b22b933Srs200217 return(r);
4427*4b22b933Srs200217 }
4428*4b22b933Srs200217
GetCacheGroup(mDNS * const m,const mDNSu32 slot,const ResourceRecord * const rr)4429*4b22b933Srs200217 mDNSlocal CacheGroup *GetCacheGroup(mDNS *const m, const mDNSu32 slot, const ResourceRecord *const rr)
4430*4b22b933Srs200217 {
4431*4b22b933Srs200217 mDNSu16 namelen = DomainNameLength(rr->name);
4432*4b22b933Srs200217 CacheGroup *cg = (CacheGroup*)GetCacheEntity(m, mDNSNULL);
4433*4b22b933Srs200217 if (!cg) { LogMsg("GetCacheGroup: Failed to allocate memory for %##s", rr->name->c); return(mDNSNULL); }
4434*4b22b933Srs200217 cg->next = m->rrcache_hash[slot];
4435*4b22b933Srs200217 cg->namehash = rr->namehash;
4436*4b22b933Srs200217 cg->members = mDNSNULL;
4437*4b22b933Srs200217 cg->rrcache_tail = &cg->members;
4438*4b22b933Srs200217 cg->name = (domainname*)cg->namestorage;
4439*4b22b933Srs200217 //LogMsg("GetCacheGroup: %-10s %d-byte cache name %##s",
4440*4b22b933Srs200217 // (namelen > InlineCacheGroupNameSize) ? "Allocating" : "Inline", namelen, rr->name->c);
4441*4b22b933Srs200217 if (namelen > InlineCacheGroupNameSize) cg->name = mDNSPlatformMemAllocate(namelen);
4442*4b22b933Srs200217 if (!cg->name)
4443*4b22b933Srs200217 {
4444*4b22b933Srs200217 LogMsg("GetCacheGroup: Failed to allocate name storage for %##s", rr->name->c);
4445*4b22b933Srs200217 ReleaseCacheEntity(m, (CacheEntity*)cg);
4446*4b22b933Srs200217 return(mDNSNULL);
4447*4b22b933Srs200217 }
4448*4b22b933Srs200217 AssignDomainName(cg->name, rr->name);
4449*4b22b933Srs200217
4450*4b22b933Srs200217 if (CacheGroupForRecord(m, slot, rr)) LogMsg("GetCacheGroup: Already have CacheGroup for %##s", rr->name->c);
4451*4b22b933Srs200217 m->rrcache_hash[slot] = cg;
4452*4b22b933Srs200217 if (CacheGroupForRecord(m, slot, rr) != cg) LogMsg("GetCacheGroup: Not finding CacheGroup for %##s", rr->name->c);
4453*4b22b933Srs200217
4454*4b22b933Srs200217 return(cg);
4455*4b22b933Srs200217 }
4456*4b22b933Srs200217
PurgeCacheResourceRecord(mDNS * const m,CacheRecord * rr)4457*4b22b933Srs200217 mDNSlocal void PurgeCacheResourceRecord(mDNS *const m, CacheRecord *rr)
4458*4b22b933Srs200217 {
4459*4b22b933Srs200217 // Make sure we mark this record as thoroughly expired -- we don't ever want to give
4460*4b22b933Srs200217 // a positive answer using an expired record (e.g. from an interface that has gone away).
4461*4b22b933Srs200217 // We don't want to clear CRActiveQuestion here, because that would leave the record subject to
4462*4b22b933Srs200217 // summary deletion without giving the proper callback to any questions that are monitoring it.
4463*4b22b933Srs200217 // By setting UnansweredQueries to MaxUnansweredQueries we ensure it won't trigger any further expiration queries.
4464*4b22b933Srs200217 rr->TimeRcvd = m->timenow - mDNSPlatformOneSecond * 60;
4465*4b22b933Srs200217 rr->UnansweredQueries = MaxUnansweredQueries;
4466*4b22b933Srs200217 rr->resrec.rroriginalttl = 0;
4467*4b22b933Srs200217 SetNextCacheCheckTime(m, rr);
4468*4b22b933Srs200217 }
4469*4b22b933Srs200217
mDNS_TimeNow(const mDNS * const m)4470*4b22b933Srs200217 mDNSexport mDNSs32 mDNS_TimeNow(const mDNS *const m)
4471*4b22b933Srs200217 {
4472*4b22b933Srs200217 mDNSs32 time;
4473*4b22b933Srs200217 mDNSPlatformLock(m);
4474*4b22b933Srs200217 if (m->mDNS_busy)
4475*4b22b933Srs200217 {
4476*4b22b933Srs200217 LogMsg("mDNS_TimeNow called while holding mDNS lock. This is incorrect. Code protected by lock should just use m->timenow.");
4477*4b22b933Srs200217 if (!m->timenow) LogMsg("mDNS_TimeNow: m->mDNS_busy is %ld but m->timenow not set", m->mDNS_busy);
4478*4b22b933Srs200217 }
4479*4b22b933Srs200217
4480*4b22b933Srs200217 if (m->timenow) time = m->timenow;
4481*4b22b933Srs200217 else time = mDNS_TimeNow_NoLock(m);
4482*4b22b933Srs200217 mDNSPlatformUnlock(m);
4483*4b22b933Srs200217 return(time);
4484*4b22b933Srs200217 }
4485*4b22b933Srs200217
mDNS_Execute(mDNS * const m)4486*4b22b933Srs200217 mDNSexport mDNSs32 mDNS_Execute(mDNS *const m)
4487*4b22b933Srs200217 {
4488*4b22b933Srs200217 mDNS_Lock(m); // Must grab lock before trying to read m->timenow
4489*4b22b933Srs200217
4490*4b22b933Srs200217 if (m->timenow - m->NextScheduledEvent >= 0)
4491*4b22b933Srs200217 {
4492*4b22b933Srs200217 int i;
4493*4b22b933Srs200217
4494*4b22b933Srs200217 verbosedebugf("mDNS_Execute");
4495*4b22b933Srs200217 if (m->CurrentQuestion) LogMsg("mDNS_Execute: ERROR! m->CurrentQuestion already set");
4496*4b22b933Srs200217
4497*4b22b933Srs200217 // 1. If we're past the probe suppression time, we can clear it
4498*4b22b933Srs200217 if (m->SuppressProbes && m->timenow - m->SuppressProbes >= 0) m->SuppressProbes = 0;
4499*4b22b933Srs200217
4500*4b22b933Srs200217 // 2. If it's been more than ten seconds since the last probe failure, we can clear the counter
4501*4b22b933Srs200217 if (m->NumFailedProbes && m->timenow - m->ProbeFailTime >= mDNSPlatformOneSecond * 10) m->NumFailedProbes = 0;
4502*4b22b933Srs200217
4503*4b22b933Srs200217 // 3. Purge our cache of stale old records
4504*4b22b933Srs200217 if (m->rrcache_size && m->timenow - m->NextCacheCheck >= 0)
4505*4b22b933Srs200217 {
4506*4b22b933Srs200217 mDNSu32 slot;
4507*4b22b933Srs200217 m->NextCacheCheck = m->timenow + 0x3FFFFFFF;
4508*4b22b933Srs200217 for (slot = 0; slot < CACHE_HASH_SLOTS; slot++)
4509*4b22b933Srs200217 {
4510*4b22b933Srs200217 CacheGroup **cp = &m->rrcache_hash[slot];
4511*4b22b933Srs200217 while (*cp)
4512*4b22b933Srs200217 {
4513*4b22b933Srs200217 CheckCacheExpiration(m, *cp);
4514*4b22b933Srs200217 if ((*cp)->members) cp=&(*cp)->next;
4515*4b22b933Srs200217 else ReleaseCacheGroup(m, cp);
4516*4b22b933Srs200217 }
4517*4b22b933Srs200217 }
4518*4b22b933Srs200217 LogOperation("Cache checked. Next in %ld ticks", m->NextCacheCheck - m->timenow);
4519*4b22b933Srs200217 }
4520*4b22b933Srs200217
4521*4b22b933Srs200217 // 4. See if we can answer any of our new local questions from the cache
4522*4b22b933Srs200217 for (i=0; m->NewQuestions && i<1000; i++)
4523*4b22b933Srs200217 {
4524*4b22b933Srs200217 if (m->NewQuestions->DelayAnswering && m->timenow - m->NewQuestions->DelayAnswering < 0) break;
4525*4b22b933Srs200217 AnswerNewQuestion(m);
4526*4b22b933Srs200217 }
4527*4b22b933Srs200217 if (i >= 1000) LogMsg("mDNS_Execute: AnswerNewQuestion exceeded loop limit");
4528*4b22b933Srs200217
4529*4b22b933Srs200217 for (i=0; m->NewLocalOnlyQuestions && i<1000; i++) AnswerNewLocalOnlyQuestion(m);
4530*4b22b933Srs200217 if (i >= 1000) LogMsg("mDNS_Execute: AnswerNewLocalOnlyQuestion exceeded loop limit");
4531*4b22b933Srs200217
4532*4b22b933Srs200217 for (i=0; i<1000 && m->NewLocalRecords && LocalRecordReady(m->NewLocalRecords); i++)
4533*4b22b933Srs200217 {
4534*4b22b933Srs200217 AuthRecord *rr = m->NewLocalRecords;
4535*4b22b933Srs200217 m->NewLocalRecords = m->NewLocalRecords->next;
4536*4b22b933Srs200217 AnswerLocalQuestions(m, rr, mDNStrue);
4537*4b22b933Srs200217 }
4538*4b22b933Srs200217 if (i >= 1000) LogMsg("mDNS_Execute: AnswerForNewLocalRecords exceeded loop limit");
4539*4b22b933Srs200217
4540*4b22b933Srs200217 // 5. See what packets we need to send
4541*4b22b933Srs200217 if (m->mDNSPlatformStatus != mStatus_NoError || m->SleepState) DiscardDeregistrations(m);
4542*4b22b933Srs200217 else if (m->SuppressSending == 0 || m->timenow - m->SuppressSending >= 0)
4543*4b22b933Srs200217 {
4544*4b22b933Srs200217 // If the platform code is ready, and we're not suppressing packet generation right now
4545*4b22b933Srs200217 // then send our responses, probes, and questions.
4546*4b22b933Srs200217 // We check the cache first, because there might be records close to expiring that trigger questions to refresh them.
4547*4b22b933Srs200217 // We send queries next, because there might be final-stage probes that complete their probing here, causing
4548*4b22b933Srs200217 // them to advance to announcing state, and we want those to be included in any announcements we send out.
4549*4b22b933Srs200217 // Finally, we send responses, including the previously mentioned records that just completed probing.
4550*4b22b933Srs200217 m->SuppressSending = 0;
4551*4b22b933Srs200217
4552*4b22b933Srs200217 // 6. Send Query packets. This may cause some probing records to advance to announcing state
4553*4b22b933Srs200217 if (m->timenow - m->NextScheduledQuery >= 0 || m->timenow - m->NextScheduledProbe >= 0) SendQueries(m);
4554*4b22b933Srs200217 if (m->timenow - m->NextScheduledQuery >= 0)
4555*4b22b933Srs200217 {
4556*4b22b933Srs200217 LogMsg("mDNS_Execute: SendQueries didn't send all its queries; will try again in one second");
4557*4b22b933Srs200217 m->NextScheduledQuery = m->timenow + mDNSPlatformOneSecond;
4558*4b22b933Srs200217 }
4559*4b22b933Srs200217 if (m->timenow - m->NextScheduledProbe >= 0)
4560*4b22b933Srs200217 {
4561*4b22b933Srs200217 LogMsg("mDNS_Execute: SendQueries didn't send all its probes; will try again in one second");
4562*4b22b933Srs200217 m->NextScheduledProbe = m->timenow + mDNSPlatformOneSecond;
4563*4b22b933Srs200217 }
4564*4b22b933Srs200217
4565*4b22b933Srs200217 // 7. Send Response packets, including probing records just advanced to announcing state
4566*4b22b933Srs200217 if (m->timenow - m->NextScheduledResponse >= 0) SendResponses(m);
4567*4b22b933Srs200217 if (m->timenow - m->NextScheduledResponse >= 0)
4568*4b22b933Srs200217 {
4569*4b22b933Srs200217 LogMsg("mDNS_Execute: SendResponses didn't send all its responses; will try again in one second");
4570*4b22b933Srs200217 m->NextScheduledResponse = m->timenow + mDNSPlatformOneSecond;
4571*4b22b933Srs200217 }
4572*4b22b933Srs200217 }
4573*4b22b933Srs200217
4574*4b22b933Srs200217 // Clear RandomDelay values, ready to pick a new different value next time
4575*4b22b933Srs200217 m->RandomQueryDelay = 0;
4576*4b22b933Srs200217 m->RandomReconfirmDelay = 0;
4577*4b22b933Srs200217 }
4578*4b22b933Srs200217
4579*4b22b933Srs200217 // Note about multi-threaded systems:
4580*4b22b933Srs200217 // On a multi-threaded system, some other thread could run right after the mDNS_Unlock(),
4581*4b22b933Srs200217 // performing mDNS API operations that change our next scheduled event time.
4582*4b22b933Srs200217 //
4583*4b22b933Srs200217 // On multi-threaded systems (like the current Windows implementation) that have a single main thread
4584*4b22b933Srs200217 // calling mDNS_Execute() (and other threads allowed to call mDNS API routines) it is the responsibility
4585*4b22b933Srs200217 // of the mDNSPlatformUnlock() routine to signal some kind of stateful condition variable that will
4586*4b22b933Srs200217 // signal whatever blocking primitive the main thread is using, so that it will wake up and execute one
4587*4b22b933Srs200217 // more iteration of its loop, and immediately call mDNS_Execute() again. The signal has to be stateful
4588*4b22b933Srs200217 // in the sense that if the main thread has not yet entered its blocking primitive, then as soon as it
4589*4b22b933Srs200217 // does, the state of the signal will be noticed, causing the blocking primitive to return immediately
4590*4b22b933Srs200217 // without blocking. This avoids the race condition between the signal from the other thread arriving
4591*4b22b933Srs200217 // just *before* or just *after* the main thread enters the blocking primitive.
4592*4b22b933Srs200217 //
4593*4b22b933Srs200217 // On multi-threaded systems (like the current Mac OS 9 implementation) that are entirely timer-driven,
4594*4b22b933Srs200217 // with no main mDNS_Execute() thread, it is the responsibility of the mDNSPlatformUnlock() routine to
4595*4b22b933Srs200217 // set the timer according to the m->NextScheduledEvent value, and then when the timer fires, the timer
4596*4b22b933Srs200217 // callback function should call mDNS_Execute() (and ignore the return value, which may already be stale
4597*4b22b933Srs200217 // by the time it gets to the timer callback function).
4598*4b22b933Srs200217
4599*4b22b933Srs200217 #ifndef UNICAST_DISABLED
4600*4b22b933Srs200217 uDNS_Execute(m);
4601*4b22b933Srs200217 #endif
4602*4b22b933Srs200217 mDNS_Unlock(m); // Calling mDNS_Unlock is what gives m->NextScheduledEvent its new value
4603*4b22b933Srs200217 return(m->NextScheduledEvent);
4604*4b22b933Srs200217 }
4605*4b22b933Srs200217
4606*4b22b933Srs200217 // Call mDNSCoreMachineSleep(m, mDNStrue) when the machine is about to go to sleep.
4607*4b22b933Srs200217 // Call mDNSCoreMachineSleep(m, mDNSfalse) when the machine is has just woken up.
4608*4b22b933Srs200217 // Normally, the platform support layer below mDNSCore should call this, not the client layer above.
4609*4b22b933Srs200217 // Note that sleep/wake calls do not have to be paired one-for-one; it is acceptable to call
4610*4b22b933Srs200217 // mDNSCoreMachineSleep(m, mDNSfalse) any time there is reason to believe that the machine may have just
4611*4b22b933Srs200217 // found itself in a new network environment. For example, if the Ethernet hardware indicates that the
4612*4b22b933Srs200217 // cable has just been connected, the platform support layer should call mDNSCoreMachineSleep(m, mDNSfalse)
4613*4b22b933Srs200217 // to make mDNSCore re-issue its outstanding queries, probe for record uniqueness, etc.
4614*4b22b933Srs200217 // While it is safe to call mDNSCoreMachineSleep(m, mDNSfalse) at any time, it does cause extra network
4615*4b22b933Srs200217 // traffic, so it should only be called when there is legitimate reason to believe the machine
4616*4b22b933Srs200217 // may have become attached to a new network.
mDNSCoreMachineSleep(mDNS * const m,mDNSBool sleepstate)4617*4b22b933Srs200217 mDNSexport void mDNSCoreMachineSleep(mDNS *const m, mDNSBool sleepstate)
4618*4b22b933Srs200217 {
4619*4b22b933Srs200217 AuthRecord *rr;
4620*4b22b933Srs200217
4621*4b22b933Srs200217 mDNS_Lock(m);
4622*4b22b933Srs200217
4623*4b22b933Srs200217 m->SleepState = sleepstate;
4624*4b22b933Srs200217 LogOperation("%s at %ld", sleepstate ? "Sleeping" : "Waking", m->timenow);
4625*4b22b933Srs200217
4626*4b22b933Srs200217 if (sleepstate)
4627*4b22b933Srs200217 {
4628*4b22b933Srs200217 #ifndef UNICAST_DISABLED
4629*4b22b933Srs200217 uDNS_Sleep(m);
4630*4b22b933Srs200217 #endif
4631*4b22b933Srs200217 // Mark all the records we need to deregister and send them
4632*4b22b933Srs200217 for (rr = m->ResourceRecords; rr; rr=rr->next)
4633*4b22b933Srs200217 if (rr->resrec.RecordType == kDNSRecordTypeShared && rr->RequireGoodbye)
4634*4b22b933Srs200217 rr->ImmedAnswer = mDNSInterfaceMark;
4635*4b22b933Srs200217 SendResponses(m);
4636*4b22b933Srs200217 }
4637*4b22b933Srs200217 else
4638*4b22b933Srs200217 {
4639*4b22b933Srs200217 DNSQuestion *q;
4640*4b22b933Srs200217 mDNSu32 slot;
4641*4b22b933Srs200217 CacheGroup *cg;
4642*4b22b933Srs200217 CacheRecord *cr;
4643*4b22b933Srs200217
4644*4b22b933Srs200217 #ifndef UNICAST_DISABLED
4645*4b22b933Srs200217 uDNS_Wake(m);
4646*4b22b933Srs200217 #endif
4647*4b22b933Srs200217 // 1. Retrigger all our questions
4648*4b22b933Srs200217 for (q = m->Questions; q; q=q->next) // Scan our list of questions
4649*4b22b933Srs200217 if (ActiveQuestion(q))
4650*4b22b933Srs200217 {
4651*4b22b933Srs200217 q->ThisQInterval = InitialQuestionInterval; // MUST be > zero for an active question
4652*4b22b933Srs200217 q->RequestUnicast = 2; // Set to 2 because is decremented once *before* we check it
4653*4b22b933Srs200217 q->LastQTime = m->timenow - q->ThisQInterval;
4654*4b22b933Srs200217 q->RecentAnswerPkts = 0;
4655*4b22b933Srs200217 ExpireDupSuppressInfo(q->DupSuppress, m->timenow);
4656*4b22b933Srs200217 m->NextScheduledQuery = m->timenow;
4657*4b22b933Srs200217 }
4658*4b22b933Srs200217
4659*4b22b933Srs200217 // 2. Re-validate our cache records
4660*4b22b933Srs200217 m->NextCacheCheck = m->timenow;
4661*4b22b933Srs200217 FORALL_CACHERECORDS(slot, cg, cr)
4662*4b22b933Srs200217 mDNS_Reconfirm_internal(m, cr, kDefaultReconfirmTimeForWake);
4663*4b22b933Srs200217
4664*4b22b933Srs200217 // 3. Retrigger probing and announcing for all our authoritative records
4665*4b22b933Srs200217 for (rr = m->ResourceRecords; rr; rr=rr->next)
4666*4b22b933Srs200217 {
4667*4b22b933Srs200217 if (rr->resrec.RecordType == kDNSRecordTypeVerified && !rr->DependentOn) rr->resrec.RecordType = kDNSRecordTypeUnique;
4668*4b22b933Srs200217 rr->ProbeCount = DefaultProbeCountForRecordType(rr->resrec.RecordType);
4669*4b22b933Srs200217 rr->AnnounceCount = InitialAnnounceCount;
4670*4b22b933Srs200217 rr->ThisAPInterval = DefaultAPIntervalForRecordType(rr->resrec.RecordType);
4671*4b22b933Srs200217 InitializeLastAPTime(m, rr);
4672*4b22b933Srs200217 }
4673*4b22b933Srs200217 }
4674*4b22b933Srs200217
4675*4b22b933Srs200217 mDNS_Unlock(m);
4676*4b22b933Srs200217 }
4677*4b22b933Srs200217
4678*4b22b933Srs200217 // ***************************************************************************
4679*4b22b933Srs200217 #if COMPILER_LIKES_PRAGMA_MARK
4680*4b22b933Srs200217 #pragma mark -
4681*4b22b933Srs200217 #pragma mark - Packet Reception Functions
4682*4b22b933Srs200217 #endif
4683*4b22b933Srs200217
4684*4b22b933Srs200217 #define MustSendRecord(RR) ((RR)->NR_AnswerTo || (RR)->NR_AdditionalTo)
4685*4b22b933Srs200217
GenerateUnicastResponse(const DNSMessage * const query,const mDNSu8 * const end,const mDNSInterfaceID InterfaceID,mDNSBool LegacyQuery,DNSMessage * const response,AuthRecord * ResponseRecords)4686*4b22b933Srs200217 mDNSlocal mDNSu8 *GenerateUnicastResponse(const DNSMessage *const query, const mDNSu8 *const end,
4687*4b22b933Srs200217 const mDNSInterfaceID InterfaceID, mDNSBool LegacyQuery, DNSMessage *const response, AuthRecord *ResponseRecords)
4688*4b22b933Srs200217 {
4689*4b22b933Srs200217 mDNSu8 *responseptr = response->data;
4690*4b22b933Srs200217 const mDNSu8 *const limit = response->data + sizeof(response->data);
4691*4b22b933Srs200217 const mDNSu8 *ptr = query->data;
4692*4b22b933Srs200217 AuthRecord *rr;
4693*4b22b933Srs200217 mDNSu32 maxttl = 0x70000000;
4694*4b22b933Srs200217 int i;
4695*4b22b933Srs200217
4696*4b22b933Srs200217 // Initialize the response fields so we can answer the questions
4697*4b22b933Srs200217 InitializeDNSMessage(&response->h, query->h.id, ResponseFlags);
4698*4b22b933Srs200217
4699*4b22b933Srs200217 // ***
4700*4b22b933Srs200217 // *** 1. Write out the list of questions we are actually going to answer with this packet
4701*4b22b933Srs200217 // ***
4702*4b22b933Srs200217 if (LegacyQuery)
4703*4b22b933Srs200217 {
4704*4b22b933Srs200217 maxttl = 10;
4705*4b22b933Srs200217 for (i=0; i<query->h.numQuestions; i++) // For each question...
4706*4b22b933Srs200217 {
4707*4b22b933Srs200217 DNSQuestion q;
4708*4b22b933Srs200217 ptr = getQuestion(query, ptr, end, InterfaceID, &q); // get the question...
4709*4b22b933Srs200217 if (!ptr) return(mDNSNULL);
4710*4b22b933Srs200217
4711*4b22b933Srs200217 for (rr=ResponseRecords; rr; rr=rr->NextResponse) // and search our list of proposed answers
4712*4b22b933Srs200217 {
4713*4b22b933Srs200217 if (rr->NR_AnswerTo == ptr) // If we're going to generate a record answering this question
4714*4b22b933Srs200217 { // then put the question in the question section
4715*4b22b933Srs200217 responseptr = putQuestion(response, responseptr, limit, &q.qname, q.qtype, q.qclass);
4716*4b22b933Srs200217 if (!responseptr) { debugf("GenerateUnicastResponse: Ran out of space for questions!"); return(mDNSNULL); }
4717*4b22b933Srs200217 break; // break out of the ResponseRecords loop, and go on to the next question
4718*4b22b933Srs200217 }
4719*4b22b933Srs200217 }
4720*4b22b933Srs200217 }
4721*4b22b933Srs200217
4722*4b22b933Srs200217 if (response->h.numQuestions == 0) { LogMsg("GenerateUnicastResponse: ERROR! Why no questions?"); return(mDNSNULL); }
4723*4b22b933Srs200217 }
4724*4b22b933Srs200217
4725*4b22b933Srs200217 // ***
4726*4b22b933Srs200217 // *** 2. Write Answers
4727*4b22b933Srs200217 // ***
4728*4b22b933Srs200217 for (rr=ResponseRecords; rr; rr=rr->NextResponse)
4729*4b22b933Srs200217 if (rr->NR_AnswerTo)
4730*4b22b933Srs200217 {
4731*4b22b933Srs200217 mDNSu8 *p = PutResourceRecordCappedTTL(response, responseptr, &response->h.numAnswers, &rr->resrec, maxttl);
4732*4b22b933Srs200217 if (p) responseptr = p;
4733*4b22b933Srs200217 else { debugf("GenerateUnicastResponse: Ran out of space for answers!"); response->h.flags.b[0] |= kDNSFlag0_TC; }
4734*4b22b933Srs200217 }
4735*4b22b933Srs200217
4736*4b22b933Srs200217 // ***
4737*4b22b933Srs200217 // *** 3. Write Additionals
4738*4b22b933Srs200217 // ***
4739*4b22b933Srs200217 for (rr=ResponseRecords; rr; rr=rr->NextResponse)
4740*4b22b933Srs200217 if (rr->NR_AdditionalTo && !rr->NR_AnswerTo)
4741*4b22b933Srs200217 {
4742*4b22b933Srs200217 mDNSu8 *p = PutResourceRecordCappedTTL(response, responseptr, &response->h.numAdditionals, &rr->resrec, maxttl);
4743*4b22b933Srs200217 if (p) responseptr = p;
4744*4b22b933Srs200217 else debugf("GenerateUnicastResponse: No more space for additionals");
4745*4b22b933Srs200217 }
4746*4b22b933Srs200217
4747*4b22b933Srs200217 return(responseptr);
4748*4b22b933Srs200217 }
4749*4b22b933Srs200217
4750*4b22b933Srs200217 // AuthRecord *our is our Resource Record
4751*4b22b933Srs200217 // CacheRecord *pkt is the Resource Record from the response packet we've witnessed on the network
4752*4b22b933Srs200217 // Returns 0 if there is no conflict
4753*4b22b933Srs200217 // Returns +1 if there was a conflict and we won
4754*4b22b933Srs200217 // Returns -1 if there was a conflict and we lost and have to rename
CompareRData(AuthRecord * our,CacheRecord * pkt)4755*4b22b933Srs200217 mDNSlocal int CompareRData(AuthRecord *our, CacheRecord *pkt)
4756*4b22b933Srs200217 {
4757*4b22b933Srs200217 mDNSu8 ourdata[256], *ourptr = ourdata, *ourend;
4758*4b22b933Srs200217 mDNSu8 pktdata[256], *pktptr = pktdata, *pktend;
4759*4b22b933Srs200217 if (!our) { LogMsg("CompareRData ERROR: our is NULL"); return(+1); }
4760*4b22b933Srs200217 if (!pkt) { LogMsg("CompareRData ERROR: pkt is NULL"); return(+1); }
4761*4b22b933Srs200217
4762*4b22b933Srs200217 ourend = putRData(mDNSNULL, ourdata, ourdata + sizeof(ourdata), &our->resrec);
4763*4b22b933Srs200217 pktend = putRData(mDNSNULL, pktdata, pktdata + sizeof(pktdata), &pkt->resrec);
4764*4b22b933Srs200217 while (ourptr < ourend && pktptr < pktend && *ourptr == *pktptr) { ourptr++; pktptr++; }
4765*4b22b933Srs200217 if (ourptr >= ourend && pktptr >= pktend) return(0); // If data identical, not a conflict
4766*4b22b933Srs200217
4767*4b22b933Srs200217 if (ourptr >= ourend) return(-1); // Our data ran out first; We lost
4768*4b22b933Srs200217 if (pktptr >= pktend) return(+1); // Packet data ran out first; We won
4769*4b22b933Srs200217 if (*pktptr > *ourptr) return(-1); // Our data is numerically lower; We lost
4770*4b22b933Srs200217 if (*pktptr < *ourptr) return(+1); // Packet data is numerically lower; We won
4771*4b22b933Srs200217
4772*4b22b933Srs200217 LogMsg("CompareRData ERROR: Invalid state");
4773*4b22b933Srs200217 return(-1);
4774*4b22b933Srs200217 }
4775*4b22b933Srs200217
4776*4b22b933Srs200217 // See if we have an authoritative record that's identical to this packet record,
4777*4b22b933Srs200217 // whose canonical DependentOn record is the specified master record.
4778*4b22b933Srs200217 // The DependentOn pointer is typically used for the TXT record of service registrations
4779*4b22b933Srs200217 // It indicates that there is no inherent conflict detection for the TXT record
4780*4b22b933Srs200217 // -- it depends on the SRV record to resolve name conflicts
4781*4b22b933Srs200217 // If we find any identical ResourceRecords in our authoritative list, then follow their DependentOn
4782*4b22b933Srs200217 // pointer chain (if any) to make sure we reach the canonical DependentOn record
4783*4b22b933Srs200217 // If the record has no DependentOn, then just return that record's pointer
4784*4b22b933Srs200217 // Returns NULL if we don't have any local RRs that are identical to the one from the packet
MatchDependentOn(const mDNS * const m,const CacheRecord * const pktrr,const AuthRecord * const master)4785*4b22b933Srs200217 mDNSlocal mDNSBool MatchDependentOn(const mDNS *const m, const CacheRecord *const pktrr, const AuthRecord *const master)
4786*4b22b933Srs200217 {
4787*4b22b933Srs200217 const AuthRecord *r1;
4788*4b22b933Srs200217 for (r1 = m->ResourceRecords; r1; r1=r1->next)
4789*4b22b933Srs200217 {
4790*4b22b933Srs200217 if (IdenticalResourceRecord(&r1->resrec, &pktrr->resrec))
4791*4b22b933Srs200217 {
4792*4b22b933Srs200217 const AuthRecord *r2 = r1;
4793*4b22b933Srs200217 while (r2->DependentOn) r2 = r2->DependentOn;
4794*4b22b933Srs200217 if (r2 == master) return(mDNStrue);
4795*4b22b933Srs200217 }
4796*4b22b933Srs200217 }
4797*4b22b933Srs200217 for (r1 = m->DuplicateRecords; r1; r1=r1->next)
4798*4b22b933Srs200217 {
4799*4b22b933Srs200217 if (IdenticalResourceRecord(&r1->resrec, &pktrr->resrec))
4800*4b22b933Srs200217 {
4801*4b22b933Srs200217 const AuthRecord *r2 = r1;
4802*4b22b933Srs200217 while (r2->DependentOn) r2 = r2->DependentOn;
4803*4b22b933Srs200217 if (r2 == master) return(mDNStrue);
4804*4b22b933Srs200217 }
4805*4b22b933Srs200217 }
4806*4b22b933Srs200217 return(mDNSfalse);
4807*4b22b933Srs200217 }
4808*4b22b933Srs200217
4809*4b22b933Srs200217 // Find the canonical RRSet pointer for this RR received in a packet.
4810*4b22b933Srs200217 // If we find any identical AuthRecord in our authoritative list, then follow its RRSet
4811*4b22b933Srs200217 // pointers (if any) to make sure we return the canonical member of this name/type/class
4812*4b22b933Srs200217 // Returns NULL if we don't have any local RRs that are identical to the one from the packet
FindRRSet(const mDNS * const m,const CacheRecord * const pktrr)4813*4b22b933Srs200217 mDNSlocal const AuthRecord *FindRRSet(const mDNS *const m, const CacheRecord *const pktrr)
4814*4b22b933Srs200217 {
4815*4b22b933Srs200217 const AuthRecord *rr;
4816*4b22b933Srs200217 for (rr = m->ResourceRecords; rr; rr=rr->next)
4817*4b22b933Srs200217 {
4818*4b22b933Srs200217 if (IdenticalResourceRecord(&rr->resrec, &pktrr->resrec))
4819*4b22b933Srs200217 {
4820*4b22b933Srs200217 while (rr->RRSet && rr != rr->RRSet) rr = rr->RRSet;
4821*4b22b933Srs200217 return(rr);
4822*4b22b933Srs200217 }
4823*4b22b933Srs200217 }
4824*4b22b933Srs200217 return(mDNSNULL);
4825*4b22b933Srs200217 }
4826*4b22b933Srs200217
4827*4b22b933Srs200217 // PacketRRConflict is called when we've received an RR (pktrr) which has the same name
4828*4b22b933Srs200217 // as one of our records (our) but different rdata.
4829*4b22b933Srs200217 // 1. If our record is not a type that's supposed to be unique, we don't care.
4830*4b22b933Srs200217 // 2a. If our record is marked as dependent on some other record for conflict detection, ignore this one.
4831*4b22b933Srs200217 // 2b. If the packet rr exactly matches one of our other RRs, and *that* record's DependentOn pointer
4832*4b22b933Srs200217 // points to our record, ignore this conflict (e.g. the packet record matches one of our
4833*4b22b933Srs200217 // TXT records, and that record is marked as dependent on 'our', its SRV record).
4834*4b22b933Srs200217 // 3. If we have some *other* RR that exactly matches the one from the packet, and that record and our record
4835*4b22b933Srs200217 // are members of the same RRSet, then this is not a conflict.
PacketRRConflict(const mDNS * const m,const AuthRecord * const our,const CacheRecord * const pktrr)4836*4b22b933Srs200217 mDNSlocal mDNSBool PacketRRConflict(const mDNS *const m, const AuthRecord *const our, const CacheRecord *const pktrr)
4837*4b22b933Srs200217 {
4838*4b22b933Srs200217 const AuthRecord *ourset = our->RRSet ? our->RRSet : our;
4839*4b22b933Srs200217
4840*4b22b933Srs200217 // If not supposed to be unique, not a conflict
4841*4b22b933Srs200217 if (!(our->resrec.RecordType & kDNSRecordTypeUniqueMask)) return(mDNSfalse);
4842*4b22b933Srs200217
4843*4b22b933Srs200217 // If a dependent record, not a conflict
4844*4b22b933Srs200217 if (our->DependentOn || MatchDependentOn(m, pktrr, our)) return(mDNSfalse);
4845*4b22b933Srs200217
4846*4b22b933Srs200217 // If the pktrr matches a member of ourset, not a conflict
4847*4b22b933Srs200217 if (FindRRSet(m, pktrr) == ourset) return(mDNSfalse);
4848*4b22b933Srs200217
4849*4b22b933Srs200217 // Okay, this is a conflict
4850*4b22b933Srs200217 return(mDNStrue);
4851*4b22b933Srs200217 }
4852*4b22b933Srs200217
4853*4b22b933Srs200217 // NOTE: ResolveSimultaneousProbe calls mDNS_Deregister_internal which can call a user callback, which may change
4854*4b22b933Srs200217 // the record list and/or question list.
4855*4b22b933Srs200217 // Any code walking either list must use the CurrentQuestion and/or CurrentRecord mechanism to protect against this.
ResolveSimultaneousProbe(mDNS * const m,const DNSMessage * const query,const mDNSu8 * const end,DNSQuestion * q,AuthRecord * our)4856*4b22b933Srs200217 mDNSlocal void ResolveSimultaneousProbe(mDNS *const m, const DNSMessage *const query, const mDNSu8 *const end,
4857*4b22b933Srs200217 DNSQuestion *q, AuthRecord *our)
4858*4b22b933Srs200217 {
4859*4b22b933Srs200217 int i;
4860*4b22b933Srs200217 const mDNSu8 *ptr = LocateAuthorities(query, end);
4861*4b22b933Srs200217 mDNSBool FoundUpdate = mDNSfalse;
4862*4b22b933Srs200217
4863*4b22b933Srs200217 for (i = 0; i < query->h.numAuthorities; i++)
4864*4b22b933Srs200217 {
4865*4b22b933Srs200217 ptr = GetLargeResourceRecord(m, query, ptr, end, q->InterfaceID, kDNSRecordTypePacketAuth, &m->rec);
4866*4b22b933Srs200217 if (!ptr) break;
4867*4b22b933Srs200217 if (ResourceRecordAnswersQuestion(&m->rec.r.resrec, q))
4868*4b22b933Srs200217 {
4869*4b22b933Srs200217 FoundUpdate = mDNStrue;
4870*4b22b933Srs200217 if (PacketRRConflict(m, our, &m->rec.r))
4871*4b22b933Srs200217 {
4872*4b22b933Srs200217 int result = (int)our->resrec.rrclass - (int)m->rec.r.resrec.rrclass;
4873*4b22b933Srs200217 if (!result) result = (int)our->resrec.rrtype - (int)m->rec.r.resrec.rrtype;
4874*4b22b933Srs200217 if (!result) result = CompareRData(our, &m->rec.r);
4875*4b22b933Srs200217 if (result > 0)
4876*4b22b933Srs200217 debugf("ResolveSimultaneousProbe: %##s (%s): We won", our->resrec.name->c, DNSTypeName(our->resrec.rrtype));
4877*4b22b933Srs200217 else if (result < 0)
4878*4b22b933Srs200217 {
4879*4b22b933Srs200217 debugf("ResolveSimultaneousProbe: %##s (%s): We lost", our->resrec.name->c, DNSTypeName(our->resrec.rrtype));
4880*4b22b933Srs200217 mDNS_Deregister_internal(m, our, mDNS_Dereg_conflict);
4881*4b22b933Srs200217 goto exit;
4882*4b22b933Srs200217 }
4883*4b22b933Srs200217 }
4884*4b22b933Srs200217 }
4885*4b22b933Srs200217 m->rec.r.resrec.RecordType = 0; // Clear RecordType to show we're not still using it
4886*4b22b933Srs200217 }
4887*4b22b933Srs200217 if (!FoundUpdate)
4888*4b22b933Srs200217 debugf("ResolveSimultaneousProbe: %##s (%s): No Update Record found", our->resrec.name->c, DNSTypeName(our->resrec.rrtype));
4889*4b22b933Srs200217 exit:
4890*4b22b933Srs200217 m->rec.r.resrec.RecordType = 0; // Clear RecordType to show we're not still using it
4891*4b22b933Srs200217 }
4892*4b22b933Srs200217
FindIdenticalRecordInCache(const mDNS * const m,ResourceRecord * pktrr)4893*4b22b933Srs200217 mDNSlocal CacheRecord *FindIdenticalRecordInCache(const mDNS *const m, ResourceRecord *pktrr)
4894*4b22b933Srs200217 {
4895*4b22b933Srs200217 mDNSu32 slot = HashSlot(pktrr->name);
4896*4b22b933Srs200217 CacheGroup *cg = CacheGroupForRecord(m, slot, pktrr);
4897*4b22b933Srs200217 CacheRecord *rr;
4898*4b22b933Srs200217 for (rr = cg ? cg->members : mDNSNULL; rr; rr=rr->next)
4899*4b22b933Srs200217 if (pktrr->InterfaceID == rr->resrec.InterfaceID && IdenticalResourceRecord(pktrr, &rr->resrec)) break;
4900*4b22b933Srs200217 return(rr);
4901*4b22b933Srs200217 }
4902*4b22b933Srs200217
4903*4b22b933Srs200217 // ProcessQuery examines a received query to see if we have any answers to give
ProcessQuery(mDNS * const m,const DNSMessage * const query,const mDNSu8 * const end,const mDNSAddr * srcaddr,const mDNSInterfaceID InterfaceID,mDNSBool LegacyQuery,mDNSBool QueryWasMulticast,mDNSBool QueryWasLocalUnicast,DNSMessage * const response)4904*4b22b933Srs200217 mDNSlocal mDNSu8 *ProcessQuery(mDNS *const m, const DNSMessage *const query, const mDNSu8 *const end,
4905*4b22b933Srs200217 const mDNSAddr *srcaddr, const mDNSInterfaceID InterfaceID, mDNSBool LegacyQuery, mDNSBool QueryWasMulticast,
4906*4b22b933Srs200217 mDNSBool QueryWasLocalUnicast, DNSMessage *const response)
4907*4b22b933Srs200217 {
4908*4b22b933Srs200217 mDNSBool FromLocalSubnet = AddressIsLocalSubnet(m, InterfaceID, srcaddr);
4909*4b22b933Srs200217 AuthRecord *ResponseRecords = mDNSNULL;
4910*4b22b933Srs200217 AuthRecord **nrp = &ResponseRecords;
4911*4b22b933Srs200217 CacheRecord *ExpectedAnswers = mDNSNULL; // Records in our cache we expect to see updated
4912*4b22b933Srs200217 CacheRecord **eap = &ExpectedAnswers;
4913*4b22b933Srs200217 DNSQuestion *DupQuestions = mDNSNULL; // Our questions that are identical to questions in this packet
4914*4b22b933Srs200217 DNSQuestion **dqp = &DupQuestions;
4915*4b22b933Srs200217 mDNSs32 delayresponse = 0;
4916*4b22b933Srs200217 mDNSBool SendLegacyResponse = mDNSfalse;
4917*4b22b933Srs200217 const mDNSu8 *ptr = query->data;
4918*4b22b933Srs200217 mDNSu8 *responseptr = mDNSNULL;
4919*4b22b933Srs200217 AuthRecord *rr;
4920*4b22b933Srs200217 int i;
4921*4b22b933Srs200217
4922*4b22b933Srs200217 // ***
4923*4b22b933Srs200217 // *** 1. Parse Question Section and mark potential answers
4924*4b22b933Srs200217 // ***
4925*4b22b933Srs200217 for (i=0; i<query->h.numQuestions; i++) // For each question...
4926*4b22b933Srs200217 {
4927*4b22b933Srs200217 mDNSBool QuestionNeedsMulticastResponse;
4928*4b22b933Srs200217 int NumAnswersForThisQuestion = 0;
4929*4b22b933Srs200217 DNSQuestion pktq, *q;
4930*4b22b933Srs200217 ptr = getQuestion(query, ptr, end, InterfaceID, &pktq); // get the question...
4931*4b22b933Srs200217 if (!ptr) goto exit;
4932*4b22b933Srs200217
4933*4b22b933Srs200217 // The only queries that *need* a multicast response are:
4934*4b22b933Srs200217 // * Queries sent via multicast
4935*4b22b933Srs200217 // * from port 5353
4936*4b22b933Srs200217 // * that don't have the kDNSQClass_UnicastResponse bit set
4937*4b22b933Srs200217 // These queries need multicast responses because other clients will:
4938*4b22b933Srs200217 // * suppress their own identical questions when they see these questions, and
4939*4b22b933Srs200217 // * expire their cache records if they don't see the expected responses
4940*4b22b933Srs200217 // For other queries, we may still choose to send the occasional multicast response anyway,
4941*4b22b933Srs200217 // to keep our neighbours caches warm, and for ongoing conflict detection.
4942*4b22b933Srs200217 QuestionNeedsMulticastResponse = QueryWasMulticast && !LegacyQuery && !(pktq.qclass & kDNSQClass_UnicastResponse);
4943*4b22b933Srs200217 // Clear the UnicastResponse flag -- don't want to confuse the rest of the code that follows later
4944*4b22b933Srs200217 pktq.qclass &= ~kDNSQClass_UnicastResponse;
4945*4b22b933Srs200217
4946*4b22b933Srs200217 // Note: We use the m->CurrentRecord mechanism here because calling ResolveSimultaneousProbe
4947*4b22b933Srs200217 // can result in user callbacks which may change the record list and/or question list.
4948*4b22b933Srs200217 // Also note: we just mark potential answer records here, without trying to build the
4949*4b22b933Srs200217 // "ResponseRecords" list, because we don't want to risk user callbacks deleting records
4950*4b22b933Srs200217 // from that list while we're in the middle of trying to build it.
4951*4b22b933Srs200217 if (m->CurrentRecord) LogMsg("ProcessQuery ERROR m->CurrentRecord already set");
4952*4b22b933Srs200217 m->CurrentRecord = m->ResourceRecords;
4953*4b22b933Srs200217 while (m->CurrentRecord)
4954*4b22b933Srs200217 {
4955*4b22b933Srs200217 rr = m->CurrentRecord;
4956*4b22b933Srs200217 m->CurrentRecord = rr->next;
4957*4b22b933Srs200217 if (ResourceRecordAnswersQuestion(&rr->resrec, &pktq) && (QueryWasMulticast || QueryWasLocalUnicast || rr->AllowRemoteQuery))
4958*4b22b933Srs200217 {
4959*4b22b933Srs200217 if (rr->resrec.RecordType == kDNSRecordTypeUnique)
4960*4b22b933Srs200217 ResolveSimultaneousProbe(m, query, end, &pktq, rr);
4961*4b22b933Srs200217 else if (ResourceRecordIsValidAnswer(rr))
4962*4b22b933Srs200217 {
4963*4b22b933Srs200217 NumAnswersForThisQuestion++;
4964*4b22b933Srs200217 // Notes:
4965*4b22b933Srs200217 // NR_AnswerTo pointing into query packet means "answer via immediate legacy unicast" (may *also* choose to multicast)
4966*4b22b933Srs200217 // NR_AnswerTo == (mDNSu8*)~1 means "answer via delayed unicast" (to modern querier; may promote to multicast instead)
4967*4b22b933Srs200217 // NR_AnswerTo == (mDNSu8*)~0 means "definitely answer via multicast" (can't downgrade to unicast later)
4968*4b22b933Srs200217 // If we're not multicasting this record because the kDNSQClass_UnicastResponse bit was set,
4969*4b22b933Srs200217 // but the multicast querier is not on a matching subnet (e.g. because of overalyed subnets on one link)
4970*4b22b933Srs200217 // then we'll multicast it anyway (if we unicast, the receiver will ignore it because it has an apparently non-local source)
4971*4b22b933Srs200217 if (QuestionNeedsMulticastResponse || (!FromLocalSubnet && QueryWasMulticast && !LegacyQuery))
4972*4b22b933Srs200217 {
4973*4b22b933Srs200217 // We only mark this question for sending if it is at least one second since the last time we multicast it
4974*4b22b933Srs200217 // on this interface. If it is more than a second, or LastMCInterface is different, then we may multicast it.
4975*4b22b933Srs200217 // This is to guard against the case where someone blasts us with queries as fast as they can.
4976*4b22b933Srs200217 if (m->timenow - (rr->LastMCTime + mDNSPlatformOneSecond) >= 0 ||
4977*4b22b933Srs200217 (rr->LastMCInterface != mDNSInterfaceMark && rr->LastMCInterface != InterfaceID))
4978*4b22b933Srs200217 rr->NR_AnswerTo = (mDNSu8*)~0;
4979*4b22b933Srs200217 }
4980*4b22b933Srs200217 else if (!rr->NR_AnswerTo) rr->NR_AnswerTo = LegacyQuery ? ptr : (mDNSu8*)~1;
4981*4b22b933Srs200217 }
4982*4b22b933Srs200217 }
4983*4b22b933Srs200217 }
4984*4b22b933Srs200217
4985*4b22b933Srs200217 // If we couldn't answer this question, someone else might be able to,
4986*4b22b933Srs200217 // so use random delay on response to reduce collisions
4987*4b22b933Srs200217 if (NumAnswersForThisQuestion == 0) delayresponse = mDNSPlatformOneSecond; // Divided by 50 = 20ms
4988*4b22b933Srs200217
4989*4b22b933Srs200217 // We only do the following accelerated cache expiration processing and duplicate question suppression processing
4990*4b22b933Srs200217 // for multicast queries with multicast responses.
4991*4b22b933Srs200217 // For any query generating a unicast response we don't do this because we can't assume we will see the response
4992*4b22b933Srs200217 if (QuestionNeedsMulticastResponse)
4993*4b22b933Srs200217 {
4994*4b22b933Srs200217 const mDNSu32 slot = HashSlot(&pktq.qname);
4995*4b22b933Srs200217 CacheGroup *cg = CacheGroupForName(m, slot, pktq.qnamehash, &pktq.qname);
4996*4b22b933Srs200217 CacheRecord *rr;
4997*4b22b933Srs200217
4998*4b22b933Srs200217 // Make a list indicating which of our own cache records we expect to see updated as a result of this query
4999*4b22b933Srs200217 // Note: Records larger than 1K are not habitually multicast, so don't expect those to be updated
5000*4b22b933Srs200217 for (rr = cg ? cg->members : mDNSNULL; rr; rr=rr->next)
5001*4b22b933Srs200217 if (ResourceRecordAnswersQuestion(&rr->resrec, &pktq) && rr->resrec.rdlength <= SmallRecordLimit)
5002*4b22b933Srs200217 if (!rr->NextInKAList && eap != &rr->NextInKAList)
5003*4b22b933Srs200217 {
5004*4b22b933Srs200217 *eap = rr;
5005*4b22b933Srs200217 eap = &rr->NextInKAList;
5006*4b22b933Srs200217 if (rr->MPUnansweredQ == 0 || m->timenow - rr->MPLastUnansweredQT >= mDNSPlatformOneSecond)
5007*4b22b933Srs200217 {
5008*4b22b933Srs200217 // Although MPUnansweredQ is only really used for multi-packet query processing,
5009*4b22b933Srs200217 // we increment it for both single-packet and multi-packet queries, so that it stays in sync
5010*4b22b933Srs200217 // with the MPUnansweredKA value, which by necessity is incremented for both query types.
5011*4b22b933Srs200217 rr->MPUnansweredQ++;
5012*4b22b933Srs200217 rr->MPLastUnansweredQT = m->timenow;
5013*4b22b933Srs200217 rr->MPExpectingKA = mDNStrue;
5014*4b22b933Srs200217 }
5015*4b22b933Srs200217 }
5016*4b22b933Srs200217
5017*4b22b933Srs200217 // Check if this question is the same as any of mine.
5018*4b22b933Srs200217 // We only do this for non-truncated queries. Right now it would be too complicated to try
5019*4b22b933Srs200217 // to keep track of duplicate suppression state between multiple packets, especially when we
5020*4b22b933Srs200217 // can't guarantee to receive all of the Known Answer packets that go with a particular query.
5021*4b22b933Srs200217 if (!(query->h.flags.b[0] & kDNSFlag0_TC))
5022*4b22b933Srs200217 for (q = m->Questions; q; q=q->next)
5023*4b22b933Srs200217 if (!q->Target.type && ActiveQuestion(q) && m->timenow - q->LastQTxTime > mDNSPlatformOneSecond / 4)
5024*4b22b933Srs200217 if (!q->InterfaceID || q->InterfaceID == InterfaceID)
5025*4b22b933Srs200217 if (q->NextInDQList == mDNSNULL && dqp != &q->NextInDQList)
5026*4b22b933Srs200217 if (q->qtype == pktq.qtype &&
5027*4b22b933Srs200217 q->qclass == pktq.qclass &&
5028*4b22b933Srs200217 q->qnamehash == pktq.qnamehash && SameDomainName(&q->qname, &pktq.qname))
5029*4b22b933Srs200217 { *dqp = q; dqp = &q->NextInDQList; }
5030*4b22b933Srs200217 }
5031*4b22b933Srs200217 }
5032*4b22b933Srs200217
5033*4b22b933Srs200217 // ***
5034*4b22b933Srs200217 // *** 2. Now we can safely build the list of marked answers
5035*4b22b933Srs200217 // ***
5036*4b22b933Srs200217 for (rr = m->ResourceRecords; rr; rr=rr->next) // Now build our list of potential answers
5037*4b22b933Srs200217 if (rr->NR_AnswerTo) // If we marked the record...
5038*4b22b933Srs200217 AddRecordToResponseList(&nrp, rr, mDNSNULL); // ... add it to the list
5039*4b22b933Srs200217
5040*4b22b933Srs200217 // ***
5041*4b22b933Srs200217 // *** 3. Add additional records
5042*4b22b933Srs200217 // ***
5043*4b22b933Srs200217 AddAdditionalsToResponseList(m, ResponseRecords, &nrp, InterfaceID);
5044*4b22b933Srs200217
5045*4b22b933Srs200217 // ***
5046*4b22b933Srs200217 // *** 4. Parse Answer Section and cancel any records disallowed by Known-Answer list
5047*4b22b933Srs200217 // ***
5048*4b22b933Srs200217 for (i=0; i<query->h.numAnswers; i++) // For each record in the query's answer section...
5049*4b22b933Srs200217 {
5050*4b22b933Srs200217 // Get the record...
5051*4b22b933Srs200217 AuthRecord *rr;
5052*4b22b933Srs200217 CacheRecord *ourcacherr;
5053*4b22b933Srs200217 ptr = GetLargeResourceRecord(m, query, ptr, end, InterfaceID, kDNSRecordTypePacketAns, &m->rec);
5054*4b22b933Srs200217 if (!ptr) goto exit;
5055*4b22b933Srs200217
5056*4b22b933Srs200217 // See if this Known-Answer suppresses any of our currently planned answers
5057*4b22b933Srs200217 for (rr=ResponseRecords; rr; rr=rr->NextResponse)
5058*4b22b933Srs200217 if (MustSendRecord(rr) && ShouldSuppressKnownAnswer(&m->rec.r, rr))
5059*4b22b933Srs200217 { rr->NR_AnswerTo = mDNSNULL; rr->NR_AdditionalTo = mDNSNULL; }
5060*4b22b933Srs200217
5061*4b22b933Srs200217 // See if this Known-Answer suppresses any previously scheduled answers (for multi-packet KA suppression)
5062*4b22b933Srs200217 for (rr=m->ResourceRecords; rr; rr=rr->next)
5063*4b22b933Srs200217 {
5064*4b22b933Srs200217 // If we're planning to send this answer on this interface, and only on this interface, then allow KA suppression
5065*4b22b933Srs200217 if (rr->ImmedAnswer == InterfaceID && ShouldSuppressKnownAnswer(&m->rec.r, rr))
5066*4b22b933Srs200217 {
5067*4b22b933Srs200217 if (srcaddr->type == mDNSAddrType_IPv4)
5068*4b22b933Srs200217 {
5069*4b22b933Srs200217 if (mDNSSameIPv4Address(rr->v4Requester, srcaddr->ip.v4)) rr->v4Requester = zerov4Addr;
5070*4b22b933Srs200217 }
5071*4b22b933Srs200217 else if (srcaddr->type == mDNSAddrType_IPv6)
5072*4b22b933Srs200217 {
5073*4b22b933Srs200217 if (mDNSSameIPv6Address(rr->v6Requester, srcaddr->ip.v6)) rr->v6Requester = zerov6Addr;
5074*4b22b933Srs200217 }
5075*4b22b933Srs200217 if (mDNSIPv4AddressIsZero(rr->v4Requester) && mDNSIPv6AddressIsZero(rr->v6Requester))
5076*4b22b933Srs200217 {
5077*4b22b933Srs200217 rr->ImmedAnswer = mDNSNULL;
5078*4b22b933Srs200217 rr->ImmedUnicast = mDNSfalse;
5079*4b22b933Srs200217 #if MDNS_LOG_ANSWER_SUPPRESSION_TIMES
5080*4b22b933Srs200217 LogMsg("Suppressed after%4d: %s", m->timenow - rr->ImmedAnswerMarkTime, ARDisplayString(m, rr));
5081*4b22b933Srs200217 #endif
5082*4b22b933Srs200217 }
5083*4b22b933Srs200217 }
5084*4b22b933Srs200217 }
5085*4b22b933Srs200217
5086*4b22b933Srs200217 // See if this Known-Answer suppresses any answers we were expecting for our cache records. We do this always,
5087*4b22b933Srs200217 // even if the TC bit is not set (the TC bit will *not* be set in the *last* packet of a multi-packet KA list).
5088*4b22b933Srs200217 ourcacherr = FindIdenticalRecordInCache(m, &m->rec.r.resrec);
5089*4b22b933Srs200217 if (ourcacherr && ourcacherr->MPExpectingKA && m->timenow - ourcacherr->MPLastUnansweredQT < mDNSPlatformOneSecond)
5090*4b22b933Srs200217 {
5091*4b22b933Srs200217 ourcacherr->MPUnansweredKA++;
5092*4b22b933Srs200217 ourcacherr->MPExpectingKA = mDNSfalse;
5093*4b22b933Srs200217 }
5094*4b22b933Srs200217
5095*4b22b933Srs200217 // Having built our ExpectedAnswers list from the questions in this packet, we can definitively
5096*4b22b933Srs200217 // remove from our ExpectedAnswers list any records that are suppressed in the very same packet.
5097*4b22b933Srs200217 // For answers that are suppressed in subsequent KA list packets, we rely on the MPQ/MPKA counting to track them.
5098*4b22b933Srs200217 eap = &ExpectedAnswers;
5099*4b22b933Srs200217 while (*eap)
5100*4b22b933Srs200217 {
5101*4b22b933Srs200217 CacheRecord *rr = *eap;
5102*4b22b933Srs200217 if (rr->resrec.InterfaceID == InterfaceID && IdenticalResourceRecord(&m->rec.r.resrec, &rr->resrec))
5103*4b22b933Srs200217 { *eap = rr->NextInKAList; rr->NextInKAList = mDNSNULL; }
5104*4b22b933Srs200217 else eap = &rr->NextInKAList;
5105*4b22b933Srs200217 }
5106*4b22b933Srs200217
5107*4b22b933Srs200217 // See if this Known-Answer is a surprise to us. If so, we shouldn't suppress our own query.
5108*4b22b933Srs200217 if (!ourcacherr)
5109*4b22b933Srs200217 {
5110*4b22b933Srs200217 dqp = &DupQuestions;
5111*4b22b933Srs200217 while (*dqp)
5112*4b22b933Srs200217 {
5113*4b22b933Srs200217 DNSQuestion *q = *dqp;
5114*4b22b933Srs200217 if (ResourceRecordAnswersQuestion(&m->rec.r.resrec, q))
5115*4b22b933Srs200217 { *dqp = q->NextInDQList; q->NextInDQList = mDNSNULL; }
5116*4b22b933Srs200217 else dqp = &q->NextInDQList;
5117*4b22b933Srs200217 }
5118*4b22b933Srs200217 }
5119*4b22b933Srs200217 m->rec.r.resrec.RecordType = 0; // Clear RecordType to show we're not still using it
5120*4b22b933Srs200217 }
5121*4b22b933Srs200217
5122*4b22b933Srs200217 // ***
5123*4b22b933Srs200217 // *** 5. Cancel any additionals that were added because of now-deleted records
5124*4b22b933Srs200217 // ***
5125*4b22b933Srs200217 for (rr=ResponseRecords; rr; rr=rr->NextResponse)
5126*4b22b933Srs200217 if (rr->NR_AdditionalTo && !MustSendRecord(rr->NR_AdditionalTo))
5127*4b22b933Srs200217 { rr->NR_AnswerTo = mDNSNULL; rr->NR_AdditionalTo = mDNSNULL; }
5128*4b22b933Srs200217
5129*4b22b933Srs200217 // ***
5130*4b22b933Srs200217 // *** 6. Mark the send flags on the records we plan to send
5131*4b22b933Srs200217 // ***
5132*4b22b933Srs200217 for (rr=ResponseRecords; rr; rr=rr->NextResponse)
5133*4b22b933Srs200217 {
5134*4b22b933Srs200217 if (rr->NR_AnswerTo)
5135*4b22b933Srs200217 {
5136*4b22b933Srs200217 mDNSBool SendMulticastResponse = mDNSfalse; // Send modern multicast response
5137*4b22b933Srs200217 mDNSBool SendUnicastResponse = mDNSfalse; // Send modern unicast response (not legacy unicast response)
5138*4b22b933Srs200217
5139*4b22b933Srs200217 // If it's been a while since we multicast this, then send a multicast response for conflict detection, etc.
5140*4b22b933Srs200217 if (m->timenow - (rr->LastMCTime + TicksTTL(rr)/4) >= 0)
5141*4b22b933Srs200217 {
5142*4b22b933Srs200217 SendMulticastResponse = mDNStrue;
5143*4b22b933Srs200217 // If this record was marked for modern (delayed) unicast response, then mark it as promoted to
5144*4b22b933Srs200217 // multicast response instead (don't want to end up ALSO setting SendUnicastResponse in the check below).
5145*4b22b933Srs200217 // If this record was marked for legacy unicast response, then we mustn't change the NR_AnswerTo value.
5146*4b22b933Srs200217 if (rr->NR_AnswerTo == (mDNSu8*)~1) rr->NR_AnswerTo = (mDNSu8*)~0;
5147*4b22b933Srs200217 }
5148*4b22b933Srs200217
5149*4b22b933Srs200217 // If the client insists on a multicast response, then we'd better send one
5150*4b22b933Srs200217 if (rr->NR_AnswerTo == (mDNSu8*)~0) SendMulticastResponse = mDNStrue;
5151*4b22b933Srs200217 else if (rr->NR_AnswerTo == (mDNSu8*)~1) SendUnicastResponse = mDNStrue;
5152*4b22b933Srs200217 else if (rr->NR_AnswerTo) SendLegacyResponse = mDNStrue;
5153*4b22b933Srs200217
5154*4b22b933Srs200217 if (SendMulticastResponse || SendUnicastResponse)
5155*4b22b933Srs200217 {
5156*4b22b933Srs200217 #if MDNS_LOG_ANSWER_SUPPRESSION_TIMES
5157*4b22b933Srs200217 rr->ImmedAnswerMarkTime = m->timenow;
5158*4b22b933Srs200217 #endif
5159*4b22b933Srs200217 m->NextScheduledResponse = m->timenow;
5160*4b22b933Srs200217 // If we're already planning to send this on another interface, just send it on all interfaces
5161*4b22b933Srs200217 if (rr->ImmedAnswer && rr->ImmedAnswer != InterfaceID)
5162*4b22b933Srs200217 rr->ImmedAnswer = mDNSInterfaceMark;
5163*4b22b933Srs200217 else
5164*4b22b933Srs200217 {
5165*4b22b933Srs200217 rr->ImmedAnswer = InterfaceID; // Record interface to send it on
5166*4b22b933Srs200217 if (SendUnicastResponse) rr->ImmedUnicast = mDNStrue;
5167*4b22b933Srs200217 if (srcaddr->type == mDNSAddrType_IPv4)
5168*4b22b933Srs200217 {
5169*4b22b933Srs200217 if (mDNSIPv4AddressIsZero(rr->v4Requester)) rr->v4Requester = srcaddr->ip.v4;
5170*4b22b933Srs200217 else if (!mDNSSameIPv4Address(rr->v4Requester, srcaddr->ip.v4)) rr->v4Requester = onesIPv4Addr;
5171*4b22b933Srs200217 }
5172*4b22b933Srs200217 else if (srcaddr->type == mDNSAddrType_IPv6)
5173*4b22b933Srs200217 {
5174*4b22b933Srs200217 if (mDNSIPv6AddressIsZero(rr->v6Requester)) rr->v6Requester = srcaddr->ip.v6;
5175*4b22b933Srs200217 else if (!mDNSSameIPv6Address(rr->v6Requester, srcaddr->ip.v6)) rr->v6Requester = onesIPv6Addr;
5176*4b22b933Srs200217 }
5177*4b22b933Srs200217 }
5178*4b22b933Srs200217 }
5179*4b22b933Srs200217 // If TC flag is set, it means we should expect that additional known answers may be coming in another packet,
5180*4b22b933Srs200217 // so we allow roughly half a second before deciding to reply (we've observed inter-packet delays of 100-200ms on 802.11)
5181*4b22b933Srs200217 // else, if record is a shared one, spread responses over 100ms to avoid implosion of simultaneous responses
5182*4b22b933Srs200217 // else, for a simple unique record reply, we can reply immediately; no need for delay
5183*4b22b933Srs200217 if (query->h.flags.b[0] & kDNSFlag0_TC) delayresponse = mDNSPlatformOneSecond * 20; // Divided by 50 = 400ms
5184*4b22b933Srs200217 else if (rr->resrec.RecordType == kDNSRecordTypeShared) delayresponse = mDNSPlatformOneSecond; // Divided by 50 = 20ms
5185*4b22b933Srs200217 }
5186*4b22b933Srs200217 else if (rr->NR_AdditionalTo && rr->NR_AdditionalTo->NR_AnswerTo == (mDNSu8*)~0)
5187*4b22b933Srs200217 {
5188*4b22b933Srs200217 // Since additional records are an optimization anyway, we only ever send them on one interface at a time
5189*4b22b933Srs200217 // If two clients on different interfaces do queries that invoke the same optional additional answer,
5190*4b22b933Srs200217 // then the earlier client is out of luck
5191*4b22b933Srs200217 rr->ImmedAdditional = InterfaceID;
5192*4b22b933Srs200217 // No need to set m->NextScheduledResponse here
5193*4b22b933Srs200217 // We'll send these additional records when we send them, or not, as the case may be
5194*4b22b933Srs200217 }
5195*4b22b933Srs200217 }
5196*4b22b933Srs200217
5197*4b22b933Srs200217 // ***
5198*4b22b933Srs200217 // *** 7. If we think other machines are likely to answer these questions, set our packet suppression timer
5199*4b22b933Srs200217 // ***
5200*4b22b933Srs200217 if (delayresponse && (!m->SuppressSending || (m->SuppressSending - m->timenow) < (delayresponse + 49) / 50))
5201*4b22b933Srs200217 {
5202*4b22b933Srs200217 #if MDNS_LOG_ANSWER_SUPPRESSION_TIMES
5203*4b22b933Srs200217 mDNSs32 oldss = m->SuppressSending;
5204*4b22b933Srs200217 if (oldss && delayresponse)
5205*4b22b933Srs200217 LogMsg("Current SuppressSending delay%5ld; require%5ld", m->SuppressSending - m->timenow, (delayresponse + 49) / 50);
5206*4b22b933Srs200217 #endif
5207*4b22b933Srs200217 // Pick a random delay:
5208*4b22b933Srs200217 // We start with the base delay chosen above (typically either 1 second or 20 seconds),
5209*4b22b933Srs200217 // and add a random value in the range 0-5 seconds (making 1-6 seconds or 20-25 seconds).
5210*4b22b933Srs200217 // This is an integer value, with resolution determined by the platform clock rate.
5211*4b22b933Srs200217 // We then divide that by 50 to get the delay value in ticks. We defer the division until last
5212*4b22b933Srs200217 // to get better results on platforms with coarse clock granularity (e.g. ten ticks per second).
5213*4b22b933Srs200217 // The +49 before dividing is to ensure we round up, not down, to ensure that even
5214*4b22b933Srs200217 // on platforms where the native clock rate is less than fifty ticks per second,
5215*4b22b933Srs200217 // we still guarantee that the final calculated delay is at least one platform tick.
5216*4b22b933Srs200217 // We want to make sure we don't ever allow the delay to be zero ticks,
5217*4b22b933Srs200217 // because if that happens we'll fail the Bonjour Conformance Test.
5218*4b22b933Srs200217 // Our final computed delay is 20-120ms for normal delayed replies,
5219*4b22b933Srs200217 // or 400-500ms in the case of multi-packet known-answer lists.
5220*4b22b933Srs200217 m->SuppressSending = m->timenow + (delayresponse + (mDNSs32)mDNSRandom((mDNSu32)mDNSPlatformOneSecond*5) + 49) / 50;
5221*4b22b933Srs200217 if (m->SuppressSending == 0) m->SuppressSending = 1;
5222*4b22b933Srs200217 #if MDNS_LOG_ANSWER_SUPPRESSION_TIMES
5223*4b22b933Srs200217 if (oldss && delayresponse)
5224*4b22b933Srs200217 LogMsg("Set SuppressSending to %5ld", m->SuppressSending - m->timenow);
5225*4b22b933Srs200217 #endif
5226*4b22b933Srs200217 }
5227*4b22b933Srs200217
5228*4b22b933Srs200217 // ***
5229*4b22b933Srs200217 // *** 8. If query is from a legacy client, or from a new client requesting a unicast reply, then generate a unicast response too
5230*4b22b933Srs200217 // ***
5231*4b22b933Srs200217 if (SendLegacyResponse)
5232*4b22b933Srs200217 responseptr = GenerateUnicastResponse(query, end, InterfaceID, LegacyQuery, response, ResponseRecords);
5233*4b22b933Srs200217
5234*4b22b933Srs200217 exit:
5235*4b22b933Srs200217 m->rec.r.resrec.RecordType = 0; // Clear RecordType to show we're not still using it
5236*4b22b933Srs200217
5237*4b22b933Srs200217 // ***
5238*4b22b933Srs200217 // *** 9. Finally, clear our link chains ready for use next time
5239*4b22b933Srs200217 // ***
5240*4b22b933Srs200217 while (ResponseRecords)
5241*4b22b933Srs200217 {
5242*4b22b933Srs200217 rr = ResponseRecords;
5243*4b22b933Srs200217 ResponseRecords = rr->NextResponse;
5244*4b22b933Srs200217 rr->NextResponse = mDNSNULL;
5245*4b22b933Srs200217 rr->NR_AnswerTo = mDNSNULL;
5246*4b22b933Srs200217 rr->NR_AdditionalTo = mDNSNULL;
5247*4b22b933Srs200217 }
5248*4b22b933Srs200217
5249*4b22b933Srs200217 while (ExpectedAnswers)
5250*4b22b933Srs200217 {
5251*4b22b933Srs200217 CacheRecord *rr;
5252*4b22b933Srs200217 rr = ExpectedAnswers;
5253*4b22b933Srs200217 ExpectedAnswers = rr->NextInKAList;
5254*4b22b933Srs200217 rr->NextInKAList = mDNSNULL;
5255*4b22b933Srs200217
5256*4b22b933Srs200217 // For non-truncated queries, we can definitively say that we should expect
5257*4b22b933Srs200217 // to be seeing a response for any records still left in the ExpectedAnswers list
5258*4b22b933Srs200217 if (!(query->h.flags.b[0] & kDNSFlag0_TC))
5259*4b22b933Srs200217 if (rr->UnansweredQueries == 0 || m->timenow - rr->LastUnansweredTime >= mDNSPlatformOneSecond)
5260*4b22b933Srs200217 {
5261*4b22b933Srs200217 rr->UnansweredQueries++;
5262*4b22b933Srs200217 rr->LastUnansweredTime = m->timenow;
5263*4b22b933Srs200217 if (rr->UnansweredQueries > 1)
5264*4b22b933Srs200217 debugf("ProcessQuery: (!TC) UAQ %lu MPQ %lu MPKA %lu %s",
5265*4b22b933Srs200217 rr->UnansweredQueries, rr->MPUnansweredQ, rr->MPUnansweredKA, CRDisplayString(m, rr));
5266*4b22b933Srs200217 SetNextCacheCheckTime(m, rr);
5267*4b22b933Srs200217 }
5268*4b22b933Srs200217
5269*4b22b933Srs200217 // If we've seen multiple unanswered queries for this record,
5270*4b22b933Srs200217 // then mark it to expire in five seconds if we don't get a response by then.
5271*4b22b933Srs200217 if (rr->UnansweredQueries >= MaxUnansweredQueries)
5272*4b22b933Srs200217 {
5273*4b22b933Srs200217 // Only show debugging message if this record was not about to expire anyway
5274*4b22b933Srs200217 if (RRExpireTime(rr) - m->timenow > 4 * mDNSPlatformOneSecond)
5275*4b22b933Srs200217 debugf("ProcessQuery: (Max) UAQ %lu MPQ %lu MPKA %lu mDNS_Reconfirm() for %s",
5276*4b22b933Srs200217 rr->UnansweredQueries, rr->MPUnansweredQ, rr->MPUnansweredKA, CRDisplayString(m, rr));
5277*4b22b933Srs200217 mDNS_Reconfirm_internal(m, rr, kDefaultReconfirmTimeForNoAnswer);
5278*4b22b933Srs200217 }
5279*4b22b933Srs200217 // Make a guess, based on the multi-packet query / known answer counts, whether we think we
5280*4b22b933Srs200217 // should have seen an answer for this. (We multiply MPQ by 4 and MPKA by 5, to allow for
5281*4b22b933Srs200217 // possible packet loss of up to 20% of the additional KA packets.)
5282*4b22b933Srs200217 else if (rr->MPUnansweredQ * 4 > rr->MPUnansweredKA * 5 + 8)
5283*4b22b933Srs200217 {
5284*4b22b933Srs200217 // We want to do this conservatively.
5285*4b22b933Srs200217 // If there are so many machines on the network that they have to use multi-packet known-answer lists,
5286*4b22b933Srs200217 // then we don't want them to all hit the network simultaneously with their final expiration queries.
5287*4b22b933Srs200217 // By setting the record to expire in four minutes, we achieve two things:
5288*4b22b933Srs200217 // (a) the 90-95% final expiration queries will be less bunched together
5289*4b22b933Srs200217 // (b) we allow some time for us to witness enough other failed queries that we don't have to do our own
5290*4b22b933Srs200217 mDNSu32 remain = (mDNSu32)(RRExpireTime(rr) - m->timenow) / 4;
5291*4b22b933Srs200217 if (remain > 240 * (mDNSu32)mDNSPlatformOneSecond)
5292*4b22b933Srs200217 remain = 240 * (mDNSu32)mDNSPlatformOneSecond;
5293*4b22b933Srs200217
5294*4b22b933Srs200217 // Only show debugging message if this record was not about to expire anyway
5295*4b22b933Srs200217 if (RRExpireTime(rr) - m->timenow > 4 * mDNSPlatformOneSecond)
5296*4b22b933Srs200217 debugf("ProcessQuery: (MPQ) UAQ %lu MPQ %lu MPKA %lu mDNS_Reconfirm() for %s",
5297*4b22b933Srs200217 rr->UnansweredQueries, rr->MPUnansweredQ, rr->MPUnansweredKA, CRDisplayString(m, rr));
5298*4b22b933Srs200217
5299*4b22b933Srs200217 if (remain <= 60 * (mDNSu32)mDNSPlatformOneSecond)
5300*4b22b933Srs200217 rr->UnansweredQueries++; // Treat this as equivalent to one definite unanswered query
5301*4b22b933Srs200217 rr->MPUnansweredQ = 0; // Clear MPQ/MPKA statistics
5302*4b22b933Srs200217 rr->MPUnansweredKA = 0;
5303*4b22b933Srs200217 rr->MPExpectingKA = mDNSfalse;
5304*4b22b933Srs200217
5305*4b22b933Srs200217 if (remain < kDefaultReconfirmTimeForNoAnswer)
5306*4b22b933Srs200217 remain = kDefaultReconfirmTimeForNoAnswer;
5307*4b22b933Srs200217 mDNS_Reconfirm_internal(m, rr, remain);
5308*4b22b933Srs200217 }
5309*4b22b933Srs200217 }
5310*4b22b933Srs200217
5311*4b22b933Srs200217 while (DupQuestions)
5312*4b22b933Srs200217 {
5313*4b22b933Srs200217 int i;
5314*4b22b933Srs200217 DNSQuestion *q = DupQuestions;
5315*4b22b933Srs200217 DupQuestions = q->NextInDQList;
5316*4b22b933Srs200217 q->NextInDQList = mDNSNULL;
5317*4b22b933Srs200217 i = RecordDupSuppressInfo(q->DupSuppress, m->timenow, InterfaceID, srcaddr->type);
5318*4b22b933Srs200217 debugf("ProcessQuery: Recorded DSI for %##s (%s) on %p/%s %d", q->qname.c, DNSTypeName(q->qtype), InterfaceID,
5319*4b22b933Srs200217 srcaddr->type == mDNSAddrType_IPv4 ? "v4" : "v6", i);
5320*4b22b933Srs200217 }
5321*4b22b933Srs200217
5322*4b22b933Srs200217 return(responseptr);
5323*4b22b933Srs200217 }
5324*4b22b933Srs200217
mDNSCoreReceiveQuery(mDNS * const m,const DNSMessage * const msg,const mDNSu8 * const end,const mDNSAddr * srcaddr,const mDNSIPPort srcport,const mDNSAddr * dstaddr,mDNSIPPort dstport,const mDNSInterfaceID InterfaceID)5325*4b22b933Srs200217 mDNSlocal void mDNSCoreReceiveQuery(mDNS *const m, const DNSMessage *const msg, const mDNSu8 *const end,
5326*4b22b933Srs200217 const mDNSAddr *srcaddr, const mDNSIPPort srcport, const mDNSAddr *dstaddr, mDNSIPPort dstport,
5327*4b22b933Srs200217 const mDNSInterfaceID InterfaceID)
5328*4b22b933Srs200217 {
5329*4b22b933Srs200217 mDNSu8 *responseend = mDNSNULL;
5330*4b22b933Srs200217 mDNSBool QueryWasLocalUnicast = !mDNSAddrIsDNSMulticast(dstaddr) && AddressIsLocalSubnet(m, InterfaceID, srcaddr);
5331*4b22b933Srs200217
5332*4b22b933Srs200217 if (!InterfaceID && mDNSAddrIsDNSMulticast(dstaddr))
5333*4b22b933Srs200217 {
5334*4b22b933Srs200217 LogMsg("Ignoring Query from %#-15a:%-5d to %#-15a:%-5d on 0x%p with "
5335*4b22b933Srs200217 "%2d Question%s %2d Answer%s %2d Authorit%s %2d Additional%s (Multicast, but no InterfaceID)",
5336*4b22b933Srs200217 srcaddr, mDNSVal16(srcport), dstaddr, mDNSVal16(dstport), InterfaceID,
5337*4b22b933Srs200217 msg->h.numQuestions, msg->h.numQuestions == 1 ? ", " : "s,",
5338*4b22b933Srs200217 msg->h.numAnswers, msg->h.numAnswers == 1 ? ", " : "s,",
5339*4b22b933Srs200217 msg->h.numAuthorities, msg->h.numAuthorities == 1 ? "y, " : "ies,",
5340*4b22b933Srs200217 msg->h.numAdditionals, msg->h.numAdditionals == 1 ? "" : "s");
5341*4b22b933Srs200217 return;
5342*4b22b933Srs200217 }
5343*4b22b933Srs200217
5344*4b22b933Srs200217 verbosedebugf("Received Query from %#-15a:%-5d to %#-15a:%-5d on 0x%p with "
5345*4b22b933Srs200217 "%2d Question%s %2d Answer%s %2d Authorit%s %2d Additional%s",
5346*4b22b933Srs200217 srcaddr, mDNSVal16(srcport), dstaddr, mDNSVal16(dstport), InterfaceID,
5347*4b22b933Srs200217 msg->h.numQuestions, msg->h.numQuestions == 1 ? ", " : "s,",
5348*4b22b933Srs200217 msg->h.numAnswers, msg->h.numAnswers == 1 ? ", " : "s,",
5349*4b22b933Srs200217 msg->h.numAuthorities, msg->h.numAuthorities == 1 ? "y, " : "ies,",
5350*4b22b933Srs200217 msg->h.numAdditionals, msg->h.numAdditionals == 1 ? "" : "s");
5351*4b22b933Srs200217
5352*4b22b933Srs200217 responseend = ProcessQuery(m, msg, end, srcaddr, InterfaceID,
5353*4b22b933Srs200217 (srcport.NotAnInteger != MulticastDNSPort.NotAnInteger), mDNSAddrIsDNSMulticast(dstaddr), QueryWasLocalUnicast, &m->omsg);
5354*4b22b933Srs200217
5355*4b22b933Srs200217 if (responseend) // If responseend is non-null, that means we built a unicast response packet
5356*4b22b933Srs200217 {
5357*4b22b933Srs200217 debugf("Unicast Response: %d Question%s, %d Answer%s, %d Additional%s to %#-15a:%d on %p/%ld",
5358*4b22b933Srs200217 m->omsg.h.numQuestions, m->omsg.h.numQuestions == 1 ? "" : "s",
5359*4b22b933Srs200217 m->omsg.h.numAnswers, m->omsg.h.numAnswers == 1 ? "" : "s",
5360*4b22b933Srs200217 m->omsg.h.numAdditionals, m->omsg.h.numAdditionals == 1 ? "" : "s",
5361*4b22b933Srs200217 srcaddr, mDNSVal16(srcport), InterfaceID, srcaddr->type);
5362*4b22b933Srs200217 mDNSSendDNSMessage(m, &m->omsg, responseend, InterfaceID, srcaddr, srcport, -1, mDNSNULL);
5363*4b22b933Srs200217 }
5364*4b22b933Srs200217 }
5365*4b22b933Srs200217
5366*4b22b933Srs200217 // NOTE: mDNSCoreReceiveResponse calls mDNS_Deregister_internal which can call a user callback, which may change
5367*4b22b933Srs200217 // the record list and/or question list.
5368*4b22b933Srs200217 // Any code walking either list must use the CurrentQuestion and/or CurrentRecord mechanism to protect against this.
mDNSCoreReceiveResponse(mDNS * const m,const DNSMessage * const response,const mDNSu8 * end,const mDNSAddr * srcaddr,const mDNSIPPort srcport,const mDNSAddr * dstaddr,mDNSIPPort dstport,const mDNSInterfaceID InterfaceID)5369*4b22b933Srs200217 mDNSlocal void mDNSCoreReceiveResponse(mDNS *const m,
5370*4b22b933Srs200217 const DNSMessage *const response, const mDNSu8 *end,
5371*4b22b933Srs200217 const mDNSAddr *srcaddr, const mDNSIPPort srcport, const mDNSAddr *dstaddr, mDNSIPPort dstport,
5372*4b22b933Srs200217 const mDNSInterfaceID InterfaceID)
5373*4b22b933Srs200217 {
5374*4b22b933Srs200217 int i;
5375*4b22b933Srs200217
5376*4b22b933Srs200217 // We ignore questions (if any) in a DNS response packet
5377*4b22b933Srs200217 const mDNSu8 *ptr = LocateAnswers(response, end);
5378*4b22b933Srs200217
5379*4b22b933Srs200217 // "(CacheRecord*)1" is a special (non-zero) end-of-list marker
5380*4b22b933Srs200217 // We use this non-zero marker so that records in our CacheFlushRecords list will always have NextInCFList
5381*4b22b933Srs200217 // set non-zero, and that tells GetCacheEntity() that they're not, at this moment, eligible for recycling.
5382*4b22b933Srs200217 CacheRecord *CacheFlushRecords = (CacheRecord*)1;
5383*4b22b933Srs200217 CacheRecord **cfp = &CacheFlushRecords;
5384*4b22b933Srs200217
5385*4b22b933Srs200217 // All records in a DNS response packet are treated as equally valid statements of truth. If we want
5386*4b22b933Srs200217 // to guard against spoof responses, then the only credible protection against that is cryptographic
5387*4b22b933Srs200217 // security, e.g. DNSSEC., not worring about which section in the spoof packet contained the record
5388*4b22b933Srs200217 int totalrecords = response->h.numAnswers + response->h.numAuthorities + response->h.numAdditionals;
5389*4b22b933Srs200217
5390*4b22b933Srs200217 (void)srcaddr; // Currently used only for display in debugging message
5391*4b22b933Srs200217 (void)srcport;
5392*4b22b933Srs200217 (void)dstport;
5393*4b22b933Srs200217
5394*4b22b933Srs200217 verbosedebugf("Received Response from %#-15a addressed to %#-15a on %p with "
5395*4b22b933Srs200217 "%2d Question%s %2d Answer%s %2d Authorit%s %2d Additional%s",
5396*4b22b933Srs200217 srcaddr, dstaddr, InterfaceID,
5397*4b22b933Srs200217 response->h.numQuestions, response->h.numQuestions == 1 ? ", " : "s,",
5398*4b22b933Srs200217 response->h.numAnswers, response->h.numAnswers == 1 ? ", " : "s,",
5399*4b22b933Srs200217 response->h.numAuthorities, response->h.numAuthorities == 1 ? "y, " : "ies,",
5400*4b22b933Srs200217 response->h.numAdditionals, response->h.numAdditionals == 1 ? "" : "s");
5401*4b22b933Srs200217
5402*4b22b933Srs200217 // If we get a unicast response when we weren't expecting one, then we assume it is someone trying to spoof us
5403*4b22b933Srs200217 if (!mDNSAddrIsDNSMulticast(dstaddr))
5404*4b22b933Srs200217 {
5405*4b22b933Srs200217 if (!AddressIsLocalSubnet(m, InterfaceID, srcaddr) || (mDNSu32)(m->timenow - m->ExpectUnicastResponse) > (mDNSu32)(mDNSPlatformOneSecond*2))
5406*4b22b933Srs200217 return;
5407*4b22b933Srs200217 // For now we don't put standard wide-area unicast responses in our main cache
5408*4b22b933Srs200217 // (Later we should fix this and cache all known results in a unified manner.)
5409*4b22b933Srs200217 if (response->h.id.NotAnInteger != 0 || srcport.NotAnInteger != MulticastDNSPort.NotAnInteger)
5410*4b22b933Srs200217 return;
5411*4b22b933Srs200217 }
5412*4b22b933Srs200217
5413*4b22b933Srs200217 for (i = 0; i < totalrecords && ptr && ptr < end; i++)
5414*4b22b933Srs200217 {
5415*4b22b933Srs200217 const mDNSu8 RecordType = (mDNSu8)((i < response->h.numAnswers) ? kDNSRecordTypePacketAns : kDNSRecordTypePacketAdd);
5416*4b22b933Srs200217 ptr = GetLargeResourceRecord(m, response, ptr, end, InterfaceID, RecordType, &m->rec);
5417*4b22b933Srs200217 if (!ptr) goto exit; // Break out of the loop and clean up our CacheFlushRecords list before exiting
5418*4b22b933Srs200217
5419*4b22b933Srs200217 // 1. Check that this packet resource record does not conflict with any of ours
5420*4b22b933Srs200217 if (m->CurrentRecord) LogMsg("mDNSCoreReceiveResponse ERROR m->CurrentRecord already set");
5421*4b22b933Srs200217 m->CurrentRecord = m->ResourceRecords;
5422*4b22b933Srs200217 while (m->CurrentRecord)
5423*4b22b933Srs200217 {
5424*4b22b933Srs200217 AuthRecord *rr = m->CurrentRecord;
5425*4b22b933Srs200217 m->CurrentRecord = rr->next;
5426*4b22b933Srs200217 if (PacketRRMatchesSignature(&m->rec.r, rr)) // If interface, name, type (if shared record) and class match...
5427*4b22b933Srs200217 {
5428*4b22b933Srs200217 // ... check to see if type and rdata are identical
5429*4b22b933Srs200217 if (m->rec.r.resrec.rrtype == rr->resrec.rrtype && SameRData(&m->rec.r.resrec, &rr->resrec))
5430*4b22b933Srs200217 {
5431*4b22b933Srs200217 // If the RR in the packet is identical to ours, just check they're not trying to lower the TTL on us
5432*4b22b933Srs200217 if (m->rec.r.resrec.rroriginalttl >= rr->resrec.rroriginalttl/2 || m->SleepState)
5433*4b22b933Srs200217 {
5434*4b22b933Srs200217 // If we were planning to send on this -- and only this -- interface, then we don't need to any more
5435*4b22b933Srs200217 if (rr->ImmedAnswer == InterfaceID) { rr->ImmedAnswer = mDNSNULL; rr->ImmedUnicast = mDNSfalse; }
5436*4b22b933Srs200217 }
5437*4b22b933Srs200217 else
5438*4b22b933Srs200217 {
5439*4b22b933Srs200217 if (rr->ImmedAnswer == mDNSNULL) { rr->ImmedAnswer = InterfaceID; m->NextScheduledResponse = m->timenow; }
5440*4b22b933Srs200217 else if (rr->ImmedAnswer != InterfaceID) { rr->ImmedAnswer = mDNSInterfaceMark; m->NextScheduledResponse = m->timenow; }
5441*4b22b933Srs200217 }
5442*4b22b933Srs200217 }
5443*4b22b933Srs200217 // else, the packet RR has different type or different rdata -- check to see if this is a conflict
5444*4b22b933Srs200217 else if (m->rec.r.resrec.rroriginalttl > 0 && PacketRRConflict(m, rr, &m->rec.r))
5445*4b22b933Srs200217 {
5446*4b22b933Srs200217 debugf("mDNSCoreReceiveResponse: Our Record: %08lX %s", rr-> resrec.rdatahash, ARDisplayString(m, rr));
5447*4b22b933Srs200217 debugf("mDNSCoreReceiveResponse: Pkt Record: %08lX %s", m->rec.r.resrec.rdatahash, CRDisplayString(m, &m->rec.r));
5448*4b22b933Srs200217
5449*4b22b933Srs200217 // If this record is marked DependentOn another record for conflict detection purposes,
5450*4b22b933Srs200217 // then *that* record has to be bumped back to probing state to resolve the conflict
5451*4b22b933Srs200217 while (rr->DependentOn) rr = rr->DependentOn;
5452*4b22b933Srs200217
5453*4b22b933Srs200217 // If we've just whacked this record's ProbeCount, don't need to do it again
5454*4b22b933Srs200217 if (rr->ProbeCount <= DefaultProbeCountForTypeUnique)
5455*4b22b933Srs200217 {
5456*4b22b933Srs200217 // If we'd previously verified this record, put it back to probing state and try again
5457*4b22b933Srs200217 if (rr->resrec.RecordType == kDNSRecordTypeVerified)
5458*4b22b933Srs200217 {
5459*4b22b933Srs200217 debugf("mDNSCoreReceiveResponse: Reseting to Probing: %##s (%s)", rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype));
5460*4b22b933Srs200217 rr->resrec.RecordType = kDNSRecordTypeUnique;
5461*4b22b933Srs200217 rr->ProbeCount = DefaultProbeCountForTypeUnique + 1;
5462*4b22b933Srs200217 rr->ThisAPInterval = DefaultAPIntervalForRecordType(kDNSRecordTypeUnique);
5463*4b22b933Srs200217 InitializeLastAPTime(m, rr);
5464*4b22b933Srs200217 RecordProbeFailure(m, rr); // Repeated late conflicts also cause us to back off to the slower probing rate
5465*4b22b933Srs200217 }
5466*4b22b933Srs200217 // If we're probing for this record, we just failed
5467*4b22b933Srs200217 else if (rr->resrec.RecordType == kDNSRecordTypeUnique)
5468*4b22b933Srs200217 {
5469*4b22b933Srs200217 debugf("mDNSCoreReceiveResponse: Will rename %##s (%s)", rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype));
5470*4b22b933Srs200217 mDNS_Deregister_internal(m, rr, mDNS_Dereg_conflict);
5471*4b22b933Srs200217 }
5472*4b22b933Srs200217 // We assumed this record must be unique, but we were wrong.
5473*4b22b933Srs200217 // (e.g. There are two mDNSResponders on the same machine giving
5474*4b22b933Srs200217 // different answers for the reverse mapping record.)
5475*4b22b933Srs200217 // This is simply a misconfiguration, and we don't try to recover from it.
5476*4b22b933Srs200217 else if (rr->resrec.RecordType == kDNSRecordTypeKnownUnique)
5477*4b22b933Srs200217 {
5478*4b22b933Srs200217 debugf("mDNSCoreReceiveResponse: Unexpected conflict on %##s (%s) -- discarding our record",
5479*4b22b933Srs200217 rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype));
5480*4b22b933Srs200217 mDNS_Deregister_internal(m, rr, mDNS_Dereg_conflict);
5481*4b22b933Srs200217 }
5482*4b22b933Srs200217 else
5483*4b22b933Srs200217 debugf("mDNSCoreReceiveResponse: Unexpected record type %X %##s (%s)",
5484*4b22b933Srs200217 rr->resrec.RecordType, rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype));
5485*4b22b933Srs200217 }
5486*4b22b933Srs200217 }
5487*4b22b933Srs200217 // Else, matching signature, different type or rdata, but not a considered a conflict.
5488*4b22b933Srs200217 // If the packet record has the cache-flush bit set, then we check to see if we
5489*4b22b933Srs200217 // have any record(s) of the same type that we should re-assert to rescue them
5490*4b22b933Srs200217 // (see note about "multi-homing and bridged networks" at the end of this function).
5491*4b22b933Srs200217 else if (m->rec.r.resrec.rrtype == rr->resrec.rrtype)
5492*4b22b933Srs200217 if ((m->rec.r.resrec.RecordType & kDNSRecordTypePacketUniqueMask) && m->timenow - rr->LastMCTime > mDNSPlatformOneSecond/2)
5493*4b22b933Srs200217 { rr->ImmedAnswer = mDNSInterfaceMark; m->NextScheduledResponse = m->timenow; }
5494*4b22b933Srs200217 }
5495*4b22b933Srs200217 }
5496*4b22b933Srs200217
5497*4b22b933Srs200217 // 2. See if we want to add this packet resource record to our cache
5498*4b22b933Srs200217 if (m->rrcache_size) // Only try to cache answers if we have a cache to put them in
5499*4b22b933Srs200217 {
5500*4b22b933Srs200217 const mDNSu32 slot = HashSlot(m->rec.r.resrec.name);
5501*4b22b933Srs200217 CacheGroup *cg = CacheGroupForRecord(m, slot, &m->rec.r.resrec);
5502*4b22b933Srs200217 CacheRecord *rr;
5503*4b22b933Srs200217 // 2a. Check if this packet resource record is already in our cache
5504*4b22b933Srs200217 for (rr = cg ? cg->members : mDNSNULL; rr; rr=rr->next)
5505*4b22b933Srs200217 {
5506*4b22b933Srs200217 // If we found this exact resource record, refresh its TTL
5507*4b22b933Srs200217 if (rr->resrec.InterfaceID == InterfaceID && IdenticalResourceRecord(&m->rec.r.resrec, &rr->resrec))
5508*4b22b933Srs200217 {
5509*4b22b933Srs200217 if (m->rec.r.resrec.rdlength > InlineCacheRDSize)
5510*4b22b933Srs200217 verbosedebugf("Found record size %5d interface %p already in cache: %s",
5511*4b22b933Srs200217 m->rec.r.resrec.rdlength, InterfaceID, CRDisplayString(m, &m->rec.r));
5512*4b22b933Srs200217 rr->TimeRcvd = m->timenow;
5513*4b22b933Srs200217
5514*4b22b933Srs200217 if (m->rec.r.resrec.RecordType & kDNSRecordTypePacketUniqueMask)
5515*4b22b933Srs200217 {
5516*4b22b933Srs200217 // If this packet record has the kDNSClass_UniqueRRSet flag set, then add it to our cache flushing list
5517*4b22b933Srs200217 if (rr->NextInCFList == mDNSNULL && cfp != &rr->NextInCFList)
5518*4b22b933Srs200217 { *cfp = rr; cfp = &rr->NextInCFList; *cfp = (CacheRecord*)1; }
5519*4b22b933Srs200217
5520*4b22b933Srs200217 // If this packet record is marked unique, and our previous cached copy was not, then fix it
5521*4b22b933Srs200217 if (!(rr->resrec.RecordType & kDNSRecordTypePacketUniqueMask))
5522*4b22b933Srs200217 {
5523*4b22b933Srs200217 DNSQuestion *q;
5524*4b22b933Srs200217 for (q = m->Questions; q; q=q->next) if (ResourceRecordAnswersQuestion(&rr->resrec, q)) q->UniqueAnswers++;
5525*4b22b933Srs200217 rr->resrec.RecordType = m->rec.r.resrec.RecordType;
5526*4b22b933Srs200217 }
5527*4b22b933Srs200217 }
5528*4b22b933Srs200217
5529*4b22b933Srs200217 if (!mDNSPlatformMemSame(m->rec.r.resrec.rdata->u.data, rr->resrec.rdata->u.data, m->rec.r.resrec.rdlength))
5530*4b22b933Srs200217 {
5531*4b22b933Srs200217 // If the rdata of the packet record differs in name capitalization from the record in our cache
5532*4b22b933Srs200217 // then mDNSPlatformMemSame will detect this. In this case, throw the old record away, so that clients get
5533*4b22b933Srs200217 // a 'remove' event for the record with the old capitalization, and then an 'add' event for the new one.
5534*4b22b933Srs200217 rr->resrec.rroriginalttl = 0;
5535*4b22b933Srs200217 rr->UnansweredQueries = MaxUnansweredQueries;
5536*4b22b933Srs200217 SetNextCacheCheckTime(m, rr);
5537*4b22b933Srs200217 // DO NOT break out here -- we want to continue as if we never found it
5538*4b22b933Srs200217 }
5539*4b22b933Srs200217 else if (m->rec.r.resrec.rroriginalttl > 0)
5540*4b22b933Srs200217 {
5541*4b22b933Srs200217 rr->resrec.rroriginalttl = m->rec.r.resrec.rroriginalttl;
5542*4b22b933Srs200217 rr->UnansweredQueries = 0;
5543*4b22b933Srs200217 rr->MPUnansweredQ = 0;
5544*4b22b933Srs200217 rr->MPUnansweredKA = 0;
5545*4b22b933Srs200217 rr->MPExpectingKA = mDNSfalse;
5546*4b22b933Srs200217 SetNextCacheCheckTime(m, rr);
5547*4b22b933Srs200217 break;
5548*4b22b933Srs200217 }
5549*4b22b933Srs200217 else
5550*4b22b933Srs200217 {
5551*4b22b933Srs200217 // If the packet TTL is zero, that means we're deleting this record.
5552*4b22b933Srs200217 // To give other hosts on the network a chance to protest, we push the deletion
5553*4b22b933Srs200217 // out one second into the future. Also, we set UnansweredQueries to MaxUnansweredQueries.
5554*4b22b933Srs200217 // Otherwise, we'll do final queries for this record at 80% and 90% of its apparent
5555*4b22b933Srs200217 // lifetime (800ms and 900ms from now) which is a pointless waste of network bandwidth.
5556*4b22b933Srs200217 rr->resrec.rroriginalttl = 1;
5557*4b22b933Srs200217 rr->UnansweredQueries = MaxUnansweredQueries;
5558*4b22b933Srs200217 SetNextCacheCheckTime(m, rr);
5559*4b22b933Srs200217 break;
5560*4b22b933Srs200217 }
5561*4b22b933Srs200217 }
5562*4b22b933Srs200217 }
5563*4b22b933Srs200217
5564*4b22b933Srs200217 // If packet resource record not in our cache, add it now
5565*4b22b933Srs200217 // (unless it is just a deletion of a record we never had, in which case we don't care)
5566*4b22b933Srs200217 if (!rr && m->rec.r.resrec.rroriginalttl > 0)
5567*4b22b933Srs200217 {
5568*4b22b933Srs200217 // If we don't have a CacheGroup for this name, make one now
5569*4b22b933Srs200217 if (!cg) cg = GetCacheGroup(m, slot, &m->rec.r.resrec);
5570*4b22b933Srs200217 if (cg) rr = GetCacheRecord(m, cg, m->rec.r.resrec.rdlength); // Make a cache record, being careful not to recycle cg
5571*4b22b933Srs200217 if (!rr) NoCacheAnswer(m, &m->rec.r);
5572*4b22b933Srs200217 else
5573*4b22b933Srs200217 {
5574*4b22b933Srs200217 RData *saveptr = rr->resrec.rdata; // Save the rr->resrec.rdata pointer
5575*4b22b933Srs200217 *rr = m->rec.r; // Block copy the CacheRecord object
5576*4b22b933Srs200217 rr->resrec.rdata = saveptr; // Restore rr->resrec.rdata after the structure assignment
5577*4b22b933Srs200217 rr->resrec.name = cg->name; // And set rr->resrec.name to point into our CacheGroup header
5578*4b22b933Srs200217 if (rr->resrec.RecordType & kDNSRecordTypePacketUniqueMask)
5579*4b22b933Srs200217 { *cfp = rr; cfp = &rr->NextInCFList; *cfp = (CacheRecord*)1; }
5580*4b22b933Srs200217 // If this is an oversized record with external storage allocated, copy rdata to external storage
5581*4b22b933Srs200217 if (rr->resrec.rdata != (RData*)&rr->rdatastorage && !(m->rec.r.resrec.rdlength > InlineCacheRDSize))
5582*4b22b933Srs200217 LogMsg("rr->resrec.rdata != &rr->rdatastorage but length <= InlineCacheRDSize %##s", m->rec.r.resrec.name->c);
5583*4b22b933Srs200217 if (m->rec.r.resrec.rdlength > InlineCacheRDSize)
5584*4b22b933Srs200217 mDNSPlatformMemCopy(m->rec.r.resrec.rdata, rr->resrec.rdata, sizeofRDataHeader + m->rec.r.resrec.rdlength);
5585*4b22b933Srs200217 rr->next = mDNSNULL; // Clear 'next' pointer
5586*4b22b933Srs200217 *(cg->rrcache_tail) = rr; // Append this record to tail of cache slot list
5587*4b22b933Srs200217 cg->rrcache_tail = &(rr->next); // Advance tail pointer
5588*4b22b933Srs200217 if (rr->resrec.RecordType & kDNSRecordTypePacketUniqueMask) // If marked unique, assume we may have
5589*4b22b933Srs200217 rr->DelayDelivery = m->timenow + mDNSPlatformOneSecond; // to delay delivery of this 'add' event
5590*4b22b933Srs200217 else
5591*4b22b933Srs200217 rr->DelayDelivery = CheckForSoonToExpireRecords(m, rr->resrec.name, rr->resrec.namehash, slot);
5592*4b22b933Srs200217 CacheRecordAdd(m, rr); // CacheRecordAdd calls SetNextCacheCheckTime(m, rr); for us
5593*4b22b933Srs200217 }
5594*4b22b933Srs200217 }
5595*4b22b933Srs200217 }
5596*4b22b933Srs200217 m->rec.r.resrec.RecordType = 0; // Clear RecordType to show we're not still using it
5597*4b22b933Srs200217 }
5598*4b22b933Srs200217
5599*4b22b933Srs200217 exit:
5600*4b22b933Srs200217 m->rec.r.resrec.RecordType = 0; // Clear RecordType to show we're not still using it
5601*4b22b933Srs200217
5602*4b22b933Srs200217 // If we've just received one or more records with their cache flush bits set,
5603*4b22b933Srs200217 // then scan that cache slot to see if there are any old stale records we need to flush
5604*4b22b933Srs200217 while (CacheFlushRecords != (CacheRecord*)1)
5605*4b22b933Srs200217 {
5606*4b22b933Srs200217 CacheRecord *r1 = CacheFlushRecords, *r2;
5607*4b22b933Srs200217 const mDNSu32 slot = HashSlot(r1->resrec.name);
5608*4b22b933Srs200217 CacheGroup *cg = CacheGroupForRecord(m, slot, &r1->resrec);
5609*4b22b933Srs200217 CacheFlushRecords = CacheFlushRecords->NextInCFList;
5610*4b22b933Srs200217 r1->NextInCFList = mDNSNULL;
5611*4b22b933Srs200217 for (r2 = cg ? cg->members : mDNSNULL; r2; r2=r2->next)
5612*4b22b933Srs200217 if (SameResourceRecordSignature(&r1->resrec, &r2->resrec))
5613*4b22b933Srs200217 {
5614*4b22b933Srs200217 // If record was recently positively received
5615*4b22b933Srs200217 // (i.e. not counting goodbye packets or cache flush events that set the TTL to 1)
5616*4b22b933Srs200217 // then we need to ensure the whole RRSet has the same TTL (as required by DNS semantics)
5617*4b22b933Srs200217 if (r2->resrec.rroriginalttl > 1 && m->timenow - r2->TimeRcvd < mDNSPlatformOneSecond)
5618*4b22b933Srs200217 {
5619*4b22b933Srs200217 if (r2->resrec.rroriginalttl != r1->resrec.rroriginalttl)
5620*4b22b933Srs200217 LogMsg("Correcting TTL from %4d to %4d for %s",
5621*4b22b933Srs200217 r2->resrec.rroriginalttl, r1->resrec.rroriginalttl, CRDisplayString(m, r2));
5622*4b22b933Srs200217 r2->resrec.rroriginalttl = r1->resrec.rroriginalttl;
5623*4b22b933Srs200217 r2->TimeRcvd = m->timenow;
5624*4b22b933Srs200217 }
5625*4b22b933Srs200217 else // else, if record is old, mark it to be flushed
5626*4b22b933Srs200217 {
5627*4b22b933Srs200217 verbosedebugf("Cache flush %p X %p %s", r1, r2, CRDisplayString(m, r2));
5628*4b22b933Srs200217 // We set stale records to expire in one second.
5629*4b22b933Srs200217 // This gives the owner a chance to rescue it if necessary.
5630*4b22b933Srs200217 // This is important in the case of multi-homing and bridged networks:
5631*4b22b933Srs200217 // Suppose host X is on Ethernet. X then connects to an AirPort base station, which happens to be
5632*4b22b933Srs200217 // bridged onto the same Ethernet. When X announces its AirPort IP address with the cache-flush bit
5633*4b22b933Srs200217 // set, the AirPort packet will be bridged onto the Ethernet, and all other hosts on the Ethernet
5634*4b22b933Srs200217 // will promptly delete their cached copies of the (still valid) Ethernet IP address record.
5635*4b22b933Srs200217 // By delaying the deletion by one second, we give X a change to notice that this bridging has
5636*4b22b933Srs200217 // happened, and re-announce its Ethernet IP address to rescue it from deletion from all our caches.
5637*4b22b933Srs200217 // We set UnansweredQueries to MaxUnansweredQueries to avoid expensive and unnecessary
5638*4b22b933Srs200217 // final expiration queries for this record.
5639*4b22b933Srs200217 r2->resrec.rroriginalttl = 1;
5640*4b22b933Srs200217 r2->TimeRcvd = m->timenow;
5641*4b22b933Srs200217 r2->UnansweredQueries = MaxUnansweredQueries;
5642*4b22b933Srs200217 }
5643*4b22b933Srs200217 SetNextCacheCheckTime(m, r2);
5644*4b22b933Srs200217 }
5645*4b22b933Srs200217 if (r1->DelayDelivery) // If we were planning to delay delivery of this record, see if we still need to
5646*4b22b933Srs200217 {
5647*4b22b933Srs200217 // Note, only need to call SetNextCacheCheckTime() when DelayDelivery is set, not when it's cleared
5648*4b22b933Srs200217 r1->DelayDelivery = CheckForSoonToExpireRecords(m, r1->resrec.name, r1->resrec.namehash, slot);
5649*4b22b933Srs200217 if (!r1->DelayDelivery) CacheRecordDeferredAdd(m, r1);
5650*4b22b933Srs200217 }
5651*4b22b933Srs200217 }
5652*4b22b933Srs200217 }
5653*4b22b933Srs200217
mDNSCoreReceive(mDNS * const m,void * const pkt,const mDNSu8 * const end,const mDNSAddr * const srcaddr,const mDNSIPPort srcport,const mDNSAddr * const dstaddr,const mDNSIPPort dstport,const mDNSInterfaceID InterfaceID)5654*4b22b933Srs200217 mDNSexport void mDNSCoreReceive(mDNS *const m, void *const pkt, const mDNSu8 *const end,
5655*4b22b933Srs200217 const mDNSAddr *const srcaddr, const mDNSIPPort srcport, const mDNSAddr *const dstaddr, const mDNSIPPort dstport,
5656*4b22b933Srs200217 const mDNSInterfaceID InterfaceID)
5657*4b22b933Srs200217 {
5658*4b22b933Srs200217 DNSMessage *msg = (DNSMessage *)pkt;
5659*4b22b933Srs200217 const mDNSu8 StdQ = kDNSFlag0_QR_Query | kDNSFlag0_OP_StdQuery;
5660*4b22b933Srs200217 const mDNSu8 StdR = kDNSFlag0_QR_Response | kDNSFlag0_OP_StdQuery;
5661*4b22b933Srs200217 mDNSu8 QR_OP;
5662*4b22b933Srs200217 mDNSu8 *ptr = mDNSNULL;
5663*4b22b933Srs200217 const mDNSu8 UpdateR = kDNSFlag0_QR_Response | kDNSFlag0_OP_Update;
5664*4b22b933Srs200217
5665*4b22b933Srs200217 #ifndef UNICAST_DISABLED
5666*4b22b933Srs200217 if (srcport.NotAnInteger == NATPMPPort.NotAnInteger)
5667*4b22b933Srs200217 {
5668*4b22b933Srs200217 mDNS_Lock(m);
5669*4b22b933Srs200217 uDNS_ReceiveNATMap(m, pkt, (mDNSu16)(end - (mDNSu8 *)pkt));
5670*4b22b933Srs200217 mDNS_Unlock(m);
5671*4b22b933Srs200217 return;
5672*4b22b933Srs200217 }
5673*4b22b933Srs200217 #endif
5674*4b22b933Srs200217 if ((unsigned)(end - (mDNSu8 *)pkt) < sizeof(DNSMessageHeader)) { LogMsg("DNS Message too short"); return; }
5675*4b22b933Srs200217 QR_OP = (mDNSu8)(msg->h.flags.b[0] & kDNSFlag0_QROP_Mask);
5676*4b22b933Srs200217 // Read the integer parts which are in IETF byte-order (MSB first, LSB second)
5677*4b22b933Srs200217 ptr = (mDNSu8 *)&msg->h.numQuestions;
5678*4b22b933Srs200217 msg->h.numQuestions = (mDNSu16)((mDNSu16)ptr[0] << 8 | ptr[1]);
5679*4b22b933Srs200217 msg->h.numAnswers = (mDNSu16)((mDNSu16)ptr[2] << 8 | ptr[3]);
5680*4b22b933Srs200217 msg->h.numAuthorities = (mDNSu16)((mDNSu16)ptr[4] << 8 | ptr[5]);
5681*4b22b933Srs200217 msg->h.numAdditionals = (mDNSu16)((mDNSu16)ptr[6] << 8 | ptr[7]);
5682*4b22b933Srs200217
5683*4b22b933Srs200217 if (!m) { LogMsg("mDNSCoreReceive ERROR m is NULL"); return; }
5684*4b22b933Srs200217
5685*4b22b933Srs200217 // We use zero addresses and all-ones addresses at various places in the code to indicate special values like "no address"
5686*4b22b933Srs200217 // If we accept and try to process a packet with zero or all-ones source address, that could really mess things up
5687*4b22b933Srs200217 if (!mDNSAddressIsValid(srcaddr)) { debugf("mDNSCoreReceive ignoring packet from %#a", srcaddr); return; }
5688*4b22b933Srs200217
5689*4b22b933Srs200217 mDNS_Lock(m);
5690*4b22b933Srs200217 m->PktNum++;
5691*4b22b933Srs200217 #ifndef UNICAST_DISABLED
5692*4b22b933Srs200217 if (!mDNSAddressIsAllDNSLinkGroup(dstaddr) && (QR_OP == StdR || QR_OP == UpdateR))
5693*4b22b933Srs200217 uDNS_ReceiveMsg(m, msg, end, srcaddr, srcport, dstaddr, dstport, InterfaceID);
5694*4b22b933Srs200217 // Note: mDNSCore also needs to get access to received unicast responses
5695*4b22b933Srs200217 #endif
5696*4b22b933Srs200217 if (QR_OP == StdQ) mDNSCoreReceiveQuery (m, msg, end, srcaddr, srcport, dstaddr, dstport, InterfaceID);
5697*4b22b933Srs200217 else if (QR_OP == StdR) mDNSCoreReceiveResponse(m, msg, end, srcaddr, srcport, dstaddr, dstport, InterfaceID);
5698*4b22b933Srs200217 else if (QR_OP != UpdateR)
5699*4b22b933Srs200217 LogMsg("Unknown DNS packet type %02X%02X from %#-15a:%-5d to %#-15a:%-5d on %p (ignored)",
5700*4b22b933Srs200217 msg->h.flags.b[0], msg->h.flags.b[1], srcaddr, mDNSVal16(srcport), dstaddr, mDNSVal16(dstport), InterfaceID);
5701*4b22b933Srs200217
5702*4b22b933Srs200217 // Packet reception often causes a change to the task list:
5703*4b22b933Srs200217 // 1. Inbound queries can cause us to need to send responses
5704*4b22b933Srs200217 // 2. Conflicing response packets received from other hosts can cause us to need to send defensive responses
5705*4b22b933Srs200217 // 3. Other hosts announcing deletion of shared records can cause us to need to re-assert those records
5706*4b22b933Srs200217 // 4. Response packets that answer questions may cause our client to issue new questions
5707*4b22b933Srs200217 mDNS_Unlock(m);
5708*4b22b933Srs200217 }
5709*4b22b933Srs200217
5710*4b22b933Srs200217 // ***************************************************************************
5711*4b22b933Srs200217 #if COMPILER_LIKES_PRAGMA_MARK
5712*4b22b933Srs200217 #pragma mark -
5713*4b22b933Srs200217 #pragma mark -
5714*4b22b933Srs200217 #pragma mark - Searcher Functions
5715*4b22b933Srs200217 #endif
5716*4b22b933Srs200217
5717*4b22b933Srs200217 #define SameQTarget(A,B) (mDNSSameAddress(&(A)->Target, &(B)->Target) && (A)->TargetPort.NotAnInteger == (B)->TargetPort.NotAnInteger)
5718*4b22b933Srs200217
FindDuplicateQuestion(const mDNS * const m,const DNSQuestion * const question)5719*4b22b933Srs200217 mDNSlocal DNSQuestion *FindDuplicateQuestion(const mDNS *const m, const DNSQuestion *const question)
5720*4b22b933Srs200217 {
5721*4b22b933Srs200217 DNSQuestion *q;
5722*4b22b933Srs200217 // Note: A question can only be marked as a duplicate of one that occurs *earlier* in the list.
5723*4b22b933Srs200217 // This prevents circular references, where two questions are each marked as a duplicate of the other.
5724*4b22b933Srs200217 // Accordingly, we break out of the loop when we get to 'question', because there's no point searching
5725*4b22b933Srs200217 // further in the list.
5726*4b22b933Srs200217 for (q = m->Questions; q && q != question; q=q->next) // Scan our list of questions
5727*4b22b933Srs200217 if (q->InterfaceID == question->InterfaceID && // for another question with the same InterfaceID,
5728*4b22b933Srs200217 SameQTarget(q, question) && // and same unicast/multicast target settings
5729*4b22b933Srs200217 q->qtype == question->qtype && // type,
5730*4b22b933Srs200217 q->qclass == question->qclass && // class,
5731*4b22b933Srs200217 q->qnamehash == question->qnamehash &&
5732*4b22b933Srs200217 SameDomainName(&q->qname, &question->qname)) // and name
5733*4b22b933Srs200217 return(q);
5734*4b22b933Srs200217 return(mDNSNULL);
5735*4b22b933Srs200217 }
5736*4b22b933Srs200217
5737*4b22b933Srs200217 // This is called after a question is deleted, in case other identical questions were being
5738*4b22b933Srs200217 // suppressed as duplicates
UpdateQuestionDuplicates(mDNS * const m,const DNSQuestion * const question)5739*4b22b933Srs200217 mDNSlocal void UpdateQuestionDuplicates(mDNS *const m, const DNSQuestion *const question)
5740*4b22b933Srs200217 {
5741*4b22b933Srs200217 DNSQuestion *q;
5742*4b22b933Srs200217 for (q = m->Questions; q; q=q->next) // Scan our list of questions
5743*4b22b933Srs200217 if (q->DuplicateOf == question) // To see if any questions were referencing this as their duplicate
5744*4b22b933Srs200217 {
5745*4b22b933Srs200217 q->ThisQInterval = question->ThisQInterval;
5746*4b22b933Srs200217 q->RequestUnicast = question->RequestUnicast;
5747*4b22b933Srs200217 q->LastQTime = question->LastQTime;
5748*4b22b933Srs200217 q->RecentAnswerPkts = 0;
5749*4b22b933Srs200217 q->DuplicateOf = FindDuplicateQuestion(m, q);
5750*4b22b933Srs200217 q->LastQTxTime = question->LastQTxTime;
5751*4b22b933Srs200217 SetNextQueryTime(m,q);
5752*4b22b933Srs200217 }
5753*4b22b933Srs200217 }
5754*4b22b933Srs200217
5755*4b22b933Srs200217 #define ValidQuestionTarget(Q) (((Q)->Target.type == mDNSAddrType_IPv4 || (Q)->Target.type == mDNSAddrType_IPv6) && \
5756*4b22b933Srs200217 ((Q)->TargetPort.NotAnInteger == UnicastDNSPort.NotAnInteger || (Q)->TargetPort.NotAnInteger == MulticastDNSPort.NotAnInteger))
5757*4b22b933Srs200217
mDNS_StartQuery_internal(mDNS * const m,DNSQuestion * const question)5758*4b22b933Srs200217 mDNSlocal mStatus mDNS_StartQuery_internal(mDNS *const m, DNSQuestion *const question)
5759*4b22b933Srs200217 {
5760*4b22b933Srs200217 if (question->Target.type && !ValidQuestionTarget(question))
5761*4b22b933Srs200217 {
5762*4b22b933Srs200217 LogMsg("Warning! Target.type = %ld port = %u (Client forgot to initialize before calling mDNS_StartQuery?)",
5763*4b22b933Srs200217 question->Target.type, mDNSVal16(question->TargetPort));
5764*4b22b933Srs200217 question->Target.type = mDNSAddrType_None;
5765*4b22b933Srs200217 }
5766*4b22b933Srs200217
5767*4b22b933Srs200217 if (!question->Target.type) // No question->Target specified, so clear TargetPort and TargetQID
5768*4b22b933Srs200217 {
5769*4b22b933Srs200217 question->TargetPort = zeroIPPort;
5770*4b22b933Srs200217 question->TargetQID = zeroID;
5771*4b22b933Srs200217 }
5772*4b22b933Srs200217
5773*4b22b933Srs200217 #ifndef UNICAST_DISABLED
5774*4b22b933Srs200217 // If the client has specified 'kDNSServiceFlagsForceMulticast'
5775*4b22b933Srs200217 // then we do a multicast query on that interface, even for unicast domains.
5776*4b22b933Srs200217 if (question->InterfaceID == mDNSInterface_LocalOnly || question->ForceMCast || IsLocalDomain(&question->qname))
5777*4b22b933Srs200217 question->uDNS_info.id = zeroID;
5778*4b22b933Srs200217 else return uDNS_StartQuery(m, question);
5779*4b22b933Srs200217 #else
5780*4b22b933Srs200217 question->uDNS_info.id = zeroID;
5781*4b22b933Srs200217 #endif // UNICAST_DISABLED
5782*4b22b933Srs200217
5783*4b22b933Srs200217 //LogOperation("mDNS_StartQuery %##s (%s)", question->qname.c, DNSTypeName(question->qtype));
5784*4b22b933Srs200217
5785*4b22b933Srs200217 if (m->rrcache_size == 0) // Can't do queries if we have no cache space allocated
5786*4b22b933Srs200217 return(mStatus_NoCache);
5787*4b22b933Srs200217 else
5788*4b22b933Srs200217 {
5789*4b22b933Srs200217 int i;
5790*4b22b933Srs200217 // Note: It important that new questions are appended at the *end* of the list, not prepended at the start
5791*4b22b933Srs200217 DNSQuestion **q = &m->Questions;
5792*4b22b933Srs200217 if (question->InterfaceID == mDNSInterface_LocalOnly) q = &m->LocalOnlyQuestions;
5793*4b22b933Srs200217 while (*q && *q != question) q=&(*q)->next;
5794*4b22b933Srs200217
5795*4b22b933Srs200217 if (*q)
5796*4b22b933Srs200217 {
5797*4b22b933Srs200217 LogMsg("Error! Tried to add a question %##s (%s) that's already in the active list",
5798*4b22b933Srs200217 question->qname.c, DNSTypeName(question->qtype));
5799*4b22b933Srs200217 return(mStatus_AlreadyRegistered);
5800*4b22b933Srs200217 }
5801*4b22b933Srs200217
5802*4b22b933Srs200217 // If this question is referencing a specific interface, verify it exists
5803*4b22b933Srs200217 if (question->InterfaceID && question->InterfaceID != mDNSInterface_LocalOnly)
5804*4b22b933Srs200217 {
5805*4b22b933Srs200217 NetworkInterfaceInfo *intf;
5806*4b22b933Srs200217 for (intf = m->HostInterfaces; intf; intf = intf->next)
5807*4b22b933Srs200217 if (intf->InterfaceID == question->InterfaceID) break;
5808*4b22b933Srs200217 if (!intf)
5809*4b22b933Srs200217 LogMsg("Note: InterfaceID %p for question %##s not currently found in active interface list",
5810*4b22b933Srs200217 question->InterfaceID, question->qname.c);
5811*4b22b933Srs200217 }
5812*4b22b933Srs200217
5813*4b22b933Srs200217 if (!ValidateDomainName(&question->qname))
5814*4b22b933Srs200217 {
5815*4b22b933Srs200217 LogMsg("Attempt to start query with invalid qname %##s (%s)", question->qname.c, DNSTypeName(question->qtype));
5816*4b22b933Srs200217 return(mStatus_Invalid);
5817*4b22b933Srs200217 }
5818*4b22b933Srs200217
5819*4b22b933Srs200217 // Note: In the case where we already have the answer to this question in our cache, that may be all the client
5820*4b22b933Srs200217 // wanted, and they may immediately cancel their question. In this case, sending an actual query on the wire would
5821*4b22b933Srs200217 // be a waste. For that reason, we schedule our first query to go out in half a second. If AnswerNewQuestion() finds
5822*4b22b933Srs200217 // that we have *no* relevant answers currently in our cache, then it will accelerate that to go out immediately.
5823*4b22b933Srs200217 if (!m->RandomQueryDelay) m->RandomQueryDelay = 1 + (mDNSs32)mDNSRandom((mDNSu32)InitialQuestionInterval);
5824*4b22b933Srs200217
5825*4b22b933Srs200217 question->next = mDNSNULL;
5826*4b22b933Srs200217 question->qnamehash = DomainNameHashValue(&question->qname); // MUST do this before FindDuplicateQuestion()
5827*4b22b933Srs200217 question->DelayAnswering = CheckForSoonToExpireRecords(m, &question->qname, question->qnamehash, HashSlot(&question->qname));
5828*4b22b933Srs200217 question->ThisQInterval = InitialQuestionInterval * 2; // MUST be > zero for an active question
5829*4b22b933Srs200217 question->RequestUnicast = 2; // Set to 2 because is decremented once *before* we check it
5830*4b22b933Srs200217 question->LastQTime = m->timenow - m->RandomQueryDelay; // Avoid inter-machine synchronization
5831*4b22b933Srs200217 question->LastAnswerPktNum = m->PktNum;
5832*4b22b933Srs200217 question->RecentAnswerPkts = 0;
5833*4b22b933Srs200217 question->CurrentAnswers = 0;
5834*4b22b933Srs200217 question->LargeAnswers = 0;
5835*4b22b933Srs200217 question->UniqueAnswers = 0;
5836*4b22b933Srs200217 question->FlappingInterface = mDNSNULL;
5837*4b22b933Srs200217 question->DuplicateOf = FindDuplicateQuestion(m, question);
5838*4b22b933Srs200217 question->NextInDQList = mDNSNULL;
5839*4b22b933Srs200217 for (i=0; i<DupSuppressInfoSize; i++)
5840*4b22b933Srs200217 question->DupSuppress[i].InterfaceID = mDNSNULL;
5841*4b22b933Srs200217 // question->InterfaceID must be already set by caller
5842*4b22b933Srs200217 question->SendQNow = mDNSNULL;
5843*4b22b933Srs200217 question->SendOnAll = mDNSfalse;
5844*4b22b933Srs200217 question->LastQTxTime = m->timenow;
5845*4b22b933Srs200217
5846*4b22b933Srs200217 if (!question->DuplicateOf)
5847*4b22b933Srs200217 verbosedebugf("mDNS_StartQuery_internal: Question %##s (%s) %p %d (%p) started",
5848*4b22b933Srs200217 question->qname.c, DNSTypeName(question->qtype), question->InterfaceID,
5849*4b22b933Srs200217 question->LastQTime + question->ThisQInterval - m->timenow, question);
5850*4b22b933Srs200217 else
5851*4b22b933Srs200217 verbosedebugf("mDNS_StartQuery_internal: Question %##s (%s) %p %d (%p) duplicate of (%p)",
5852*4b22b933Srs200217 question->qname.c, DNSTypeName(question->qtype), question->InterfaceID,
5853*4b22b933Srs200217 question->LastQTime + question->ThisQInterval - m->timenow, question, question->DuplicateOf);
5854*4b22b933Srs200217
5855*4b22b933Srs200217 *q = question;
5856*4b22b933Srs200217 if (question->InterfaceID == mDNSInterface_LocalOnly)
5857*4b22b933Srs200217 {
5858*4b22b933Srs200217 if (!m->NewLocalOnlyQuestions) m->NewLocalOnlyQuestions = question;
5859*4b22b933Srs200217 }
5860*4b22b933Srs200217 else
5861*4b22b933Srs200217 {
5862*4b22b933Srs200217 if (!m->NewQuestions) m->NewQuestions = question;
5863*4b22b933Srs200217 SetNextQueryTime(m,question);
5864*4b22b933Srs200217 }
5865*4b22b933Srs200217
5866*4b22b933Srs200217 return(mStatus_NoError);
5867*4b22b933Srs200217 }
5868*4b22b933Srs200217 }
5869*4b22b933Srs200217
mDNS_StopQuery_internal(mDNS * const m,DNSQuestion * const question)5870*4b22b933Srs200217 mDNSlocal mStatus mDNS_StopQuery_internal(mDNS *const m, DNSQuestion *const question)
5871*4b22b933Srs200217 {
5872*4b22b933Srs200217 const mDNSu32 slot = HashSlot(&question->qname);
5873*4b22b933Srs200217 CacheGroup *cg = CacheGroupForName(m, slot, question->qnamehash, &question->qname);
5874*4b22b933Srs200217 CacheRecord *rr;
5875*4b22b933Srs200217 DNSQuestion **q = &m->Questions;
5876*4b22b933Srs200217
5877*4b22b933Srs200217 if (uDNS_IsActiveQuery(question, &m->uDNS_info)) return uDNS_StopQuery(m, question);
5878*4b22b933Srs200217
5879*4b22b933Srs200217 if (question->InterfaceID == mDNSInterface_LocalOnly) q = &m->LocalOnlyQuestions;
5880*4b22b933Srs200217 while (*q && *q != question) q=&(*q)->next;
5881*4b22b933Srs200217 if (*q) *q = (*q)->next;
5882*4b22b933Srs200217 else
5883*4b22b933Srs200217 {
5884*4b22b933Srs200217 if (question->ThisQInterval >= 0) // Only log error message if the query was supposed to be active
5885*4b22b933Srs200217 LogMsg("mDNS_StopQuery_internal: Question %##s (%s) not found in active list",
5886*4b22b933Srs200217 question->qname.c, DNSTypeName(question->qtype));
5887*4b22b933Srs200217 return(mStatus_BadReferenceErr);
5888*4b22b933Srs200217 }
5889*4b22b933Srs200217
5890*4b22b933Srs200217 // Take care to cut question from list *before* calling UpdateQuestionDuplicates
5891*4b22b933Srs200217 UpdateQuestionDuplicates(m, question);
5892*4b22b933Srs200217 // But don't trash ThisQInterval until afterwards.
5893*4b22b933Srs200217 question->ThisQInterval = -1;
5894*4b22b933Srs200217
5895*4b22b933Srs200217 // If there are any cache records referencing this as their active question, then see if any other
5896*4b22b933Srs200217 // question that is also referencing them, else their CRActiveQuestion needs to get set to NULL.
5897*4b22b933Srs200217 for (rr = cg ? cg->members : mDNSNULL; rr; rr=rr->next)
5898*4b22b933Srs200217 {
5899*4b22b933Srs200217 if (rr->CRActiveQuestion == question)
5900*4b22b933Srs200217 {
5901*4b22b933Srs200217 DNSQuestion *q;
5902*4b22b933Srs200217 for (q = m->Questions; q; q=q->next) // Scan our list of questions
5903*4b22b933Srs200217 if (ActiveQuestion(q) && ResourceRecordAnswersQuestion(&rr->resrec, q))
5904*4b22b933Srs200217 break;
5905*4b22b933Srs200217 verbosedebugf("mDNS_StopQuery_internal: Cache RR %##s (%s) setting CRActiveQuestion to %p",
5906*4b22b933Srs200217 rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype), q);
5907*4b22b933Srs200217 rr->CRActiveQuestion = q; // Question used to be active; new value may or may not be null
5908*4b22b933Srs200217 if (!q) m->rrcache_active--; // If no longer active, decrement rrcache_active count
5909*4b22b933Srs200217 }
5910*4b22b933Srs200217 }
5911*4b22b933Srs200217
5912*4b22b933Srs200217 // If we just deleted the question that CacheRecordAdd() or CacheRecordRmv()is about to look at,
5913*4b22b933Srs200217 // bump its pointer forward one question.
5914*4b22b933Srs200217 if (m->CurrentQuestion == question)
5915*4b22b933Srs200217 {
5916*4b22b933Srs200217 debugf("mDNS_StopQuery_internal: Just deleted the currently active question: %##s (%s)",
5917*4b22b933Srs200217 question->qname.c, DNSTypeName(question->qtype));
5918*4b22b933Srs200217 m->CurrentQuestion = question->next;
5919*4b22b933Srs200217 }
5920*4b22b933Srs200217
5921*4b22b933Srs200217 if (m->NewQuestions == question)
5922*4b22b933Srs200217 {
5923*4b22b933Srs200217 debugf("mDNS_StopQuery_internal: Just deleted a new question that wasn't even answered yet: %##s (%s)",
5924*4b22b933Srs200217 question->qname.c, DNSTypeName(question->qtype));
5925*4b22b933Srs200217 m->NewQuestions = question->next;
5926*4b22b933Srs200217 }
5927*4b22b933Srs200217
5928*4b22b933Srs200217 if (m->NewLocalOnlyQuestions == question) m->NewLocalOnlyQuestions = question->next;
5929*4b22b933Srs200217
5930*4b22b933Srs200217 // Take care not to trash question->next until *after* we've updated m->CurrentQuestion and m->NewQuestions
5931*4b22b933Srs200217 question->next = mDNSNULL;
5932*4b22b933Srs200217 return(mStatus_NoError);
5933*4b22b933Srs200217 }
5934*4b22b933Srs200217
mDNS_StartQuery(mDNS * const m,DNSQuestion * const question)5935*4b22b933Srs200217 mDNSexport mStatus mDNS_StartQuery(mDNS *const m, DNSQuestion *const question)
5936*4b22b933Srs200217 {
5937*4b22b933Srs200217 mStatus status;
5938*4b22b933Srs200217 mDNS_Lock(m);
5939*4b22b933Srs200217 status = mDNS_StartQuery_internal(m, question);
5940*4b22b933Srs200217 mDNS_Unlock(m);
5941*4b22b933Srs200217 return(status);
5942*4b22b933Srs200217 }
5943*4b22b933Srs200217
mDNS_StopQuery(mDNS * const m,DNSQuestion * const question)5944*4b22b933Srs200217 mDNSexport mStatus mDNS_StopQuery(mDNS *const m, DNSQuestion *const question)
5945*4b22b933Srs200217 {
5946*4b22b933Srs200217 mStatus status;
5947*4b22b933Srs200217 mDNS_Lock(m);
5948*4b22b933Srs200217 status = mDNS_StopQuery_internal(m, question);
5949*4b22b933Srs200217 mDNS_Unlock(m);
5950*4b22b933Srs200217 return(status);
5951*4b22b933Srs200217 }
5952*4b22b933Srs200217
mDNS_Reconfirm(mDNS * const m,CacheRecord * const rr)5953*4b22b933Srs200217 mDNSexport mStatus mDNS_Reconfirm(mDNS *const m, CacheRecord *const rr)
5954*4b22b933Srs200217 {
5955*4b22b933Srs200217 mStatus status;
5956*4b22b933Srs200217 mDNS_Lock(m);
5957*4b22b933Srs200217 status = mDNS_Reconfirm_internal(m, rr, kDefaultReconfirmTimeForNoAnswer);
5958*4b22b933Srs200217 mDNS_Unlock(m);
5959*4b22b933Srs200217 return(status);
5960*4b22b933Srs200217 }
5961*4b22b933Srs200217
mDNS_ReconfirmByValue(mDNS * const m,ResourceRecord * const rr)5962*4b22b933Srs200217 mDNSexport mStatus mDNS_ReconfirmByValue(mDNS *const m, ResourceRecord *const rr)
5963*4b22b933Srs200217 {
5964*4b22b933Srs200217 mStatus status = mStatus_BadReferenceErr;
5965*4b22b933Srs200217 CacheRecord *cr;
5966*4b22b933Srs200217 mDNS_Lock(m);
5967*4b22b933Srs200217 cr = FindIdenticalRecordInCache(m, rr);
5968*4b22b933Srs200217 if (cr) status = mDNS_Reconfirm_internal(m, cr, kDefaultReconfirmTimeForNoAnswer);
5969*4b22b933Srs200217 mDNS_Unlock(m);
5970*4b22b933Srs200217 return(status);
5971*4b22b933Srs200217 }
5972*4b22b933Srs200217
mDNS_StartBrowse(mDNS * const m,DNSQuestion * const question,const domainname * const srv,const domainname * const domain,const mDNSInterfaceID InterfaceID,mDNSBool ForceMCast,mDNSQuestionCallback * Callback,void * Context)5973*4b22b933Srs200217 mDNSexport mStatus mDNS_StartBrowse(mDNS *const m, DNSQuestion *const question,
5974*4b22b933Srs200217 const domainname *const srv, const domainname *const domain,
5975*4b22b933Srs200217 const mDNSInterfaceID InterfaceID, mDNSBool ForceMCast, mDNSQuestionCallback *Callback, void *Context)
5976*4b22b933Srs200217 {
5977*4b22b933Srs200217 question->InterfaceID = InterfaceID;
5978*4b22b933Srs200217 question->Target = zeroAddr;
5979*4b22b933Srs200217 question->qtype = kDNSType_PTR;
5980*4b22b933Srs200217 question->qclass = kDNSClass_IN;
5981*4b22b933Srs200217 question->LongLived = mDNSfalse;
5982*4b22b933Srs200217 question->ExpectUnique = mDNSfalse;
5983*4b22b933Srs200217 question->ForceMCast = ForceMCast;
5984*4b22b933Srs200217 question->QuestionCallback = Callback;
5985*4b22b933Srs200217 question->QuestionContext = Context;
5986*4b22b933Srs200217 if (!ConstructServiceName(&question->qname, mDNSNULL, srv, domain)) return(mStatus_BadParamErr);
5987*4b22b933Srs200217
5988*4b22b933Srs200217 #ifndef UNICAST_DISABLED
5989*4b22b933Srs200217 if (question->InterfaceID == mDNSInterface_LocalOnly || question->ForceMCast || IsLocalDomain(&question->qname))
5990*4b22b933Srs200217 {
5991*4b22b933Srs200217 question->LongLived = mDNSfalse;
5992*4b22b933Srs200217 question->uDNS_info.id = zeroID;
5993*4b22b933Srs200217 return(mDNS_StartQuery(m, question));
5994*4b22b933Srs200217 }
5995*4b22b933Srs200217 else
5996*4b22b933Srs200217 {
5997*4b22b933Srs200217 mStatus status;
5998*4b22b933Srs200217 // Need to explicitly lock here, because mDNS_StartQuery does locking but uDNS_StartQuery does not
5999*4b22b933Srs200217 mDNS_Lock(m);
6000*4b22b933Srs200217 question->LongLived = mDNStrue;
6001*4b22b933Srs200217 status = uDNS_StartQuery(m, question);
6002*4b22b933Srs200217 mDNS_Unlock(m);
6003*4b22b933Srs200217 return(status);
6004*4b22b933Srs200217 }
6005*4b22b933Srs200217 #else
6006*4b22b933Srs200217 return(mDNS_StartQuery(m, question));
6007*4b22b933Srs200217 #endif // UNICAST_DISABLED
6008*4b22b933Srs200217 }
6009*4b22b933Srs200217
MachineHasActiveIPv6(mDNS * const m)6010*4b22b933Srs200217 mDNSlocal mDNSBool MachineHasActiveIPv6(mDNS *const m)
6011*4b22b933Srs200217 {
6012*4b22b933Srs200217 NetworkInterfaceInfo *intf;
6013*4b22b933Srs200217 for (intf = m->HostInterfaces; intf; intf = intf->next)
6014*4b22b933Srs200217 if (intf->ip.type == mDNSAddrType_IPv6) return(mDNStrue);
6015*4b22b933Srs200217 return(mDNSfalse);
6016*4b22b933Srs200217 }
6017*4b22b933Srs200217
FoundServiceInfoSRV(mDNS * const m,DNSQuestion * question,const ResourceRecord * const answer,mDNSBool AddRecord)6018*4b22b933Srs200217 mDNSlocal void FoundServiceInfoSRV(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, mDNSBool AddRecord)
6019*4b22b933Srs200217 {
6020*4b22b933Srs200217 ServiceInfoQuery *query = (ServiceInfoQuery *)question->QuestionContext;
6021*4b22b933Srs200217 mDNSBool PortChanged = (mDNSBool)(query->info->port.NotAnInteger != answer->rdata->u.srv.port.NotAnInteger);
6022*4b22b933Srs200217 if (!AddRecord) return;
6023*4b22b933Srs200217 if (answer->rrtype != kDNSType_SRV) return;
6024*4b22b933Srs200217
6025*4b22b933Srs200217 query->info->port = answer->rdata->u.srv.port;
6026*4b22b933Srs200217
6027*4b22b933Srs200217 // If this is our first answer, then set the GotSRV flag and start the address query
6028*4b22b933Srs200217 if (!query->GotSRV)
6029*4b22b933Srs200217 {
6030*4b22b933Srs200217 query->GotSRV = mDNStrue;
6031*4b22b933Srs200217 query->qAv4.InterfaceID = answer->InterfaceID;
6032*4b22b933Srs200217 AssignDomainName(&query->qAv4.qname, &answer->rdata->u.srv.target);
6033*4b22b933Srs200217 query->qAv6.InterfaceID = answer->InterfaceID;
6034*4b22b933Srs200217 AssignDomainName(&query->qAv6.qname, &answer->rdata->u.srv.target);
6035*4b22b933Srs200217 mDNS_StartQuery(m, &query->qAv4);
6036*4b22b933Srs200217 // Only do the AAAA query if this machine actually has IPv6 active
6037*4b22b933Srs200217 if (MachineHasActiveIPv6(m)) mDNS_StartQuery(m, &query->qAv6);
6038*4b22b933Srs200217 }
6039*4b22b933Srs200217 // If this is not our first answer, only re-issue the address query if the target host name has changed
6040*4b22b933Srs200217 else if ((query->qAv4.InterfaceID != query->qSRV.InterfaceID && query->qAv4.InterfaceID != answer->InterfaceID) ||
6041*4b22b933Srs200217 !SameDomainName(&query->qAv4.qname, &answer->rdata->u.srv.target))
6042*4b22b933Srs200217 {
6043*4b22b933Srs200217 mDNS_StopQuery(m, &query->qAv4);
6044*4b22b933Srs200217 if (query->qAv6.ThisQInterval >= 0) mDNS_StopQuery(m, &query->qAv6);
6045*4b22b933Srs200217 if (SameDomainName(&query->qAv4.qname, &answer->rdata->u.srv.target) && !PortChanged)
6046*4b22b933Srs200217 {
6047*4b22b933Srs200217 // If we get here, it means:
6048*4b22b933Srs200217 // 1. This is not our first SRV answer
6049*4b22b933Srs200217 // 2. The interface ID is different, but the target host and port are the same
6050*4b22b933Srs200217 // This implies that we're seeing the exact same SRV record on more than one interface, so we should
6051*4b22b933Srs200217 // make our address queries at least as broad as the original SRV query so that we catch all the answers.
6052*4b22b933Srs200217 query->qAv4.InterfaceID = query->qSRV.InterfaceID; // Will be mDNSInterface_Any, or a specific interface
6053*4b22b933Srs200217 query->qAv6.InterfaceID = query->qSRV.InterfaceID;
6054*4b22b933Srs200217 }
6055*4b22b933Srs200217 else
6056*4b22b933Srs200217 {
6057*4b22b933Srs200217 query->qAv4.InterfaceID = answer->InterfaceID;
6058*4b22b933Srs200217 AssignDomainName(&query->qAv4.qname, &answer->rdata->u.srv.target);
6059*4b22b933Srs200217 query->qAv6.InterfaceID = answer->InterfaceID;
6060*4b22b933Srs200217 AssignDomainName(&query->qAv6.qname, &answer->rdata->u.srv.target);
6061*4b22b933Srs200217 }
6062*4b22b933Srs200217 debugf("FoundServiceInfoSRV: Restarting address queries for %##s", query->qAv4.qname.c);
6063*4b22b933Srs200217 mDNS_StartQuery(m, &query->qAv4);
6064*4b22b933Srs200217 // Only do the AAAA query if this machine actually has IPv6 active
6065*4b22b933Srs200217 if (MachineHasActiveIPv6(m)) mDNS_StartQuery(m, &query->qAv6);
6066*4b22b933Srs200217 }
6067*4b22b933Srs200217 else if (query->ServiceInfoQueryCallback && query->GotADD && query->GotTXT && PortChanged)
6068*4b22b933Srs200217 {
6069*4b22b933Srs200217 if (++query->Answers >= 100)
6070*4b22b933Srs200217 debugf("**** WARNING **** Have given %lu answers for %##s (SRV) %##s %u",
6071*4b22b933Srs200217 query->Answers, query->qSRV.qname.c, answer->rdata->u.srv.target.c,
6072*4b22b933Srs200217 mDNSVal16(answer->rdata->u.srv.port));
6073*4b22b933Srs200217 query->ServiceInfoQueryCallback(m, query);
6074*4b22b933Srs200217 }
6075*4b22b933Srs200217 // CAUTION: MUST NOT do anything more with query after calling query->Callback(), because the client's
6076*4b22b933Srs200217 // callback function is allowed to do anything, including deleting this query and freeing its memory.
6077*4b22b933Srs200217 }
6078*4b22b933Srs200217
FoundServiceInfoTXT(mDNS * const m,DNSQuestion * question,const ResourceRecord * const answer,mDNSBool AddRecord)6079*4b22b933Srs200217 mDNSlocal void FoundServiceInfoTXT(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, mDNSBool AddRecord)
6080*4b22b933Srs200217 {
6081*4b22b933Srs200217 ServiceInfoQuery *query = (ServiceInfoQuery *)question->QuestionContext;
6082*4b22b933Srs200217 if (!AddRecord) return;
6083*4b22b933Srs200217 if (answer->rrtype != kDNSType_TXT) return;
6084*4b22b933Srs200217 if (answer->rdlength > sizeof(query->info->TXTinfo)) return;
6085*4b22b933Srs200217
6086*4b22b933Srs200217 query->GotTXT = mDNStrue;
6087*4b22b933Srs200217 query->info->TXTlen = answer->rdlength;
6088*4b22b933Srs200217 query->info->TXTinfo[0] = 0; // In case answer->rdlength is zero
6089*4b22b933Srs200217 mDNSPlatformMemCopy(answer->rdata->u.txt.c, query->info->TXTinfo, answer->rdlength);
6090*4b22b933Srs200217
6091*4b22b933Srs200217 verbosedebugf("FoundServiceInfoTXT: %##s GotADD=%d", query->info->name.c, query->GotADD);
6092*4b22b933Srs200217
6093*4b22b933Srs200217 // CAUTION: MUST NOT do anything more with query after calling query->Callback(), because the client's
6094*4b22b933Srs200217 // callback function is allowed to do anything, including deleting this query and freeing its memory.
6095*4b22b933Srs200217 if (query->ServiceInfoQueryCallback && query->GotADD)
6096*4b22b933Srs200217 {
6097*4b22b933Srs200217 if (++query->Answers >= 100)
6098*4b22b933Srs200217 debugf("**** WARNING **** have given %lu answers for %##s (TXT) %#s...",
6099*4b22b933Srs200217 query->Answers, query->qSRV.qname.c, answer->rdata->u.txt.c);
6100*4b22b933Srs200217 query->ServiceInfoQueryCallback(m, query);
6101*4b22b933Srs200217 }
6102*4b22b933Srs200217 }
6103*4b22b933Srs200217
FoundServiceInfo(mDNS * const m,DNSQuestion * question,const ResourceRecord * const answer,mDNSBool AddRecord)6104*4b22b933Srs200217 mDNSlocal void FoundServiceInfo(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, mDNSBool AddRecord)
6105*4b22b933Srs200217 {
6106*4b22b933Srs200217 ServiceInfoQuery *query = (ServiceInfoQuery *)question->QuestionContext;
6107*4b22b933Srs200217 //LogOperation("FoundServiceInfo %d %s", AddRecord, RRDisplayString(m, answer));
6108*4b22b933Srs200217 if (!AddRecord) return;
6109*4b22b933Srs200217
6110*4b22b933Srs200217 if (answer->rrtype == kDNSType_A)
6111*4b22b933Srs200217 {
6112*4b22b933Srs200217 query->info->ip.type = mDNSAddrType_IPv4;
6113*4b22b933Srs200217 query->info->ip.ip.v4 = answer->rdata->u.ipv4;
6114*4b22b933Srs200217 }
6115*4b22b933Srs200217 else if (answer->rrtype == kDNSType_AAAA)
6116*4b22b933Srs200217 {
6117*4b22b933Srs200217 query->info->ip.type = mDNSAddrType_IPv6;
6118*4b22b933Srs200217 query->info->ip.ip.v6 = answer->rdata->u.ipv6;
6119*4b22b933Srs200217 }
6120*4b22b933Srs200217 else
6121*4b22b933Srs200217 {
6122*4b22b933Srs200217 debugf("FoundServiceInfo: answer %##s type %d (%s) unexpected", answer->name->c, answer->rrtype, DNSTypeName(answer->rrtype));
6123*4b22b933Srs200217 return;
6124*4b22b933Srs200217 }
6125*4b22b933Srs200217
6126*4b22b933Srs200217 query->GotADD = mDNStrue;
6127*4b22b933Srs200217 query->info->InterfaceID = answer->InterfaceID;
6128*4b22b933Srs200217
6129*4b22b933Srs200217 verbosedebugf("FoundServiceInfo v%ld: %##s GotTXT=%d", query->info->ip.type, query->info->name.c, query->GotTXT);
6130*4b22b933Srs200217
6131*4b22b933Srs200217 // CAUTION: MUST NOT do anything more with query after calling query->Callback(), because the client's
6132*4b22b933Srs200217 // callback function is allowed to do anything, including deleting this query and freeing its memory.
6133*4b22b933Srs200217 if (query->ServiceInfoQueryCallback && query->GotTXT)
6134*4b22b933Srs200217 {
6135*4b22b933Srs200217 if (++query->Answers >= 100)
6136*4b22b933Srs200217 debugf(answer->rrtype == kDNSType_A ?
6137*4b22b933Srs200217 "**** WARNING **** have given %lu answers for %##s (A) %.4a" :
6138*4b22b933Srs200217 "**** WARNING **** have given %lu answers for %##s (AAAA) %.16a",
6139*4b22b933Srs200217 query->Answers, query->qSRV.qname.c, &answer->rdata->u.data);
6140*4b22b933Srs200217 query->ServiceInfoQueryCallback(m, query);
6141*4b22b933Srs200217 }
6142*4b22b933Srs200217 }
6143*4b22b933Srs200217
6144*4b22b933Srs200217 // On entry, the client must have set the name and InterfaceID fields of the ServiceInfo structure
6145*4b22b933Srs200217 // If the query is not interface-specific, then InterfaceID may be zero
6146*4b22b933Srs200217 // Each time the Callback is invoked, the remainder of the fields will have been filled in
6147*4b22b933Srs200217 // In addition, InterfaceID will be updated to give the interface identifier corresponding to that response
mDNS_StartResolveService(mDNS * const m,ServiceInfoQuery * query,ServiceInfo * info,mDNSServiceInfoQueryCallback * Callback,void * Context)6148*4b22b933Srs200217 mDNSexport mStatus mDNS_StartResolveService(mDNS *const m,
6149*4b22b933Srs200217 ServiceInfoQuery *query, ServiceInfo *info, mDNSServiceInfoQueryCallback *Callback, void *Context)
6150*4b22b933Srs200217 {
6151*4b22b933Srs200217 mStatus status;
6152*4b22b933Srs200217 mDNS_Lock(m);
6153*4b22b933Srs200217
6154*4b22b933Srs200217 query->qSRV.ThisQInterval = -1; // So that mDNS_StopResolveService() knows whether to cancel this question
6155*4b22b933Srs200217 query->qSRV.InterfaceID = info->InterfaceID;
6156*4b22b933Srs200217 query->qSRV.Target = zeroAddr;
6157*4b22b933Srs200217 AssignDomainName(&query->qSRV.qname, &info->name);
6158*4b22b933Srs200217 query->qSRV.qtype = kDNSType_SRV;
6159*4b22b933Srs200217 query->qSRV.qclass = kDNSClass_IN;
6160*4b22b933Srs200217 query->qSRV.LongLived = mDNSfalse;
6161*4b22b933Srs200217 query->qSRV.ExpectUnique = mDNStrue;
6162*4b22b933Srs200217 query->qSRV.ForceMCast = mDNSfalse;
6163*4b22b933Srs200217 query->qSRV.QuestionCallback = FoundServiceInfoSRV;
6164*4b22b933Srs200217 query->qSRV.QuestionContext = query;
6165*4b22b933Srs200217
6166*4b22b933Srs200217 query->qTXT.ThisQInterval = -1; // So that mDNS_StopResolveService() knows whether to cancel this question
6167*4b22b933Srs200217 query->qTXT.InterfaceID = info->InterfaceID;
6168*4b22b933Srs200217 query->qTXT.Target = zeroAddr;
6169*4b22b933Srs200217 AssignDomainName(&query->qTXT.qname, &info->name);
6170*4b22b933Srs200217 query->qTXT.qtype = kDNSType_TXT;
6171*4b22b933Srs200217 query->qTXT.qclass = kDNSClass_IN;
6172*4b22b933Srs200217 query->qTXT.LongLived = mDNSfalse;
6173*4b22b933Srs200217 query->qTXT.ExpectUnique = mDNStrue;
6174*4b22b933Srs200217 query->qTXT.ForceMCast = mDNSfalse;
6175*4b22b933Srs200217 query->qTXT.QuestionCallback = FoundServiceInfoTXT;
6176*4b22b933Srs200217 query->qTXT.QuestionContext = query;
6177*4b22b933Srs200217
6178*4b22b933Srs200217 query->qAv4.ThisQInterval = -1; // So that mDNS_StopResolveService() knows whether to cancel this question
6179*4b22b933Srs200217 query->qAv4.InterfaceID = info->InterfaceID;
6180*4b22b933Srs200217 query->qAv4.Target = zeroAddr;
6181*4b22b933Srs200217 query->qAv4.qname.c[0] = 0;
6182*4b22b933Srs200217 query->qAv4.qtype = kDNSType_A;
6183*4b22b933Srs200217 query->qAv4.qclass = kDNSClass_IN;
6184*4b22b933Srs200217 query->qAv4.LongLived = mDNSfalse;
6185*4b22b933Srs200217 query->qAv4.ExpectUnique = mDNStrue;
6186*4b22b933Srs200217 query->qAv4.ForceMCast = mDNSfalse;
6187*4b22b933Srs200217 query->qAv4.QuestionCallback = FoundServiceInfo;
6188*4b22b933Srs200217 query->qAv4.QuestionContext = query;
6189*4b22b933Srs200217
6190*4b22b933Srs200217 query->qAv6.ThisQInterval = -1; // So that mDNS_StopResolveService() knows whether to cancel this question
6191*4b22b933Srs200217 query->qAv6.InterfaceID = info->InterfaceID;
6192*4b22b933Srs200217 query->qAv6.Target = zeroAddr;
6193*4b22b933Srs200217 query->qAv6.qname.c[0] = 0;
6194*4b22b933Srs200217 query->qAv6.qtype = kDNSType_AAAA;
6195*4b22b933Srs200217 query->qAv6.qclass = kDNSClass_IN;
6196*4b22b933Srs200217 query->qAv6.LongLived = mDNSfalse;
6197*4b22b933Srs200217 query->qAv6.ExpectUnique = mDNStrue;
6198*4b22b933Srs200217 query->qAv6.ForceMCast = mDNSfalse;
6199*4b22b933Srs200217 query->qAv6.QuestionCallback = FoundServiceInfo;
6200*4b22b933Srs200217 query->qAv6.QuestionContext = query;
6201*4b22b933Srs200217
6202*4b22b933Srs200217 query->GotSRV = mDNSfalse;
6203*4b22b933Srs200217 query->GotTXT = mDNSfalse;
6204*4b22b933Srs200217 query->GotADD = mDNSfalse;
6205*4b22b933Srs200217 query->Answers = 0;
6206*4b22b933Srs200217
6207*4b22b933Srs200217 query->info = info;
6208*4b22b933Srs200217 query->ServiceInfoQueryCallback = Callback;
6209*4b22b933Srs200217 query->ServiceInfoQueryContext = Context;
6210*4b22b933Srs200217
6211*4b22b933Srs200217 // info->name = Must already be set up by client
6212*4b22b933Srs200217 // info->interface = Must already be set up by client
6213*4b22b933Srs200217 info->ip = zeroAddr;
6214*4b22b933Srs200217 info->port = zeroIPPort;
6215*4b22b933Srs200217 info->TXTlen = 0;
6216*4b22b933Srs200217
6217*4b22b933Srs200217 // We use mDNS_StartQuery_internal here because we're already holding the lock
6218*4b22b933Srs200217 status = mDNS_StartQuery_internal(m, &query->qSRV);
6219*4b22b933Srs200217 if (status == mStatus_NoError) status = mDNS_StartQuery_internal(m, &query->qTXT);
6220*4b22b933Srs200217 if (status != mStatus_NoError) mDNS_StopResolveService(m, query);
6221*4b22b933Srs200217
6222*4b22b933Srs200217 mDNS_Unlock(m);
6223*4b22b933Srs200217 return(status);
6224*4b22b933Srs200217 }
6225*4b22b933Srs200217
mDNS_StopResolveService(mDNS * const m,ServiceInfoQuery * q)6226*4b22b933Srs200217 mDNSexport void mDNS_StopResolveService (mDNS *const m, ServiceInfoQuery *q)
6227*4b22b933Srs200217 {
6228*4b22b933Srs200217 mDNS_Lock(m);
6229*4b22b933Srs200217 // We use mDNS_StopQuery_internal here because we're already holding the lock
6230*4b22b933Srs200217 if (q->qSRV.ThisQInterval >= 0 || uDNS_IsActiveQuery(&q->qSRV, &m->uDNS_info)) mDNS_StopQuery_internal(m, &q->qSRV);
6231*4b22b933Srs200217 if (q->qTXT.ThisQInterval >= 0 || uDNS_IsActiveQuery(&q->qTXT, &m->uDNS_info)) mDNS_StopQuery_internal(m, &q->qTXT);
6232*4b22b933Srs200217 if (q->qAv4.ThisQInterval >= 0 || uDNS_IsActiveQuery(&q->qAv4, &m->uDNS_info)) mDNS_StopQuery_internal(m, &q->qAv4);
6233*4b22b933Srs200217 if (q->qAv6.ThisQInterval >= 0 || uDNS_IsActiveQuery(&q->qAv6, &m->uDNS_info)) mDNS_StopQuery_internal(m, &q->qAv6);
6234*4b22b933Srs200217 mDNS_Unlock(m);
6235*4b22b933Srs200217 }
6236*4b22b933Srs200217
mDNS_GetDomains(mDNS * const m,DNSQuestion * const question,mDNS_DomainType DomainType,const domainname * dom,const mDNSInterfaceID InterfaceID,mDNSQuestionCallback * Callback,void * Context)6237*4b22b933Srs200217 mDNSexport mStatus mDNS_GetDomains(mDNS *const m, DNSQuestion *const question, mDNS_DomainType DomainType, const domainname *dom,
6238*4b22b933Srs200217 const mDNSInterfaceID InterfaceID, mDNSQuestionCallback *Callback, void *Context)
6239*4b22b933Srs200217 {
6240*4b22b933Srs200217 question->InterfaceID = InterfaceID;
6241*4b22b933Srs200217 question->Target = zeroAddr;
6242*4b22b933Srs200217 question->qtype = kDNSType_PTR;
6243*4b22b933Srs200217 question->qclass = kDNSClass_IN;
6244*4b22b933Srs200217 question->LongLived = mDNSfalse;
6245*4b22b933Srs200217 question->ExpectUnique = mDNSfalse;
6246*4b22b933Srs200217 question->ForceMCast = mDNSfalse;
6247*4b22b933Srs200217 question->QuestionCallback = Callback;
6248*4b22b933Srs200217 question->QuestionContext = Context;
6249*4b22b933Srs200217 if (DomainType > mDNS_DomainTypeMax) return(mStatus_BadParamErr);
6250*4b22b933Srs200217 if (!MakeDomainNameFromDNSNameString(&question->qname, mDNS_DomainTypeNames[DomainType])) return(mStatus_BadParamErr);
6251*4b22b933Srs200217 if (!dom) dom = &localdomain;
6252*4b22b933Srs200217 if (!AppendDomainName(&question->qname, dom)) return(mStatus_BadParamErr);
6253*4b22b933Srs200217 return(mDNS_StartQuery(m, question));
6254*4b22b933Srs200217 }
6255*4b22b933Srs200217
6256*4b22b933Srs200217 // ***************************************************************************
6257*4b22b933Srs200217 #if COMPILER_LIKES_PRAGMA_MARK
6258*4b22b933Srs200217 #pragma mark -
6259*4b22b933Srs200217 #pragma mark - Responder Functions
6260*4b22b933Srs200217 #endif
6261*4b22b933Srs200217
mDNS_Register(mDNS * const m,AuthRecord * const rr)6262*4b22b933Srs200217 mDNSexport mStatus mDNS_Register(mDNS *const m, AuthRecord *const rr)
6263*4b22b933Srs200217 {
6264*4b22b933Srs200217 mStatus status;
6265*4b22b933Srs200217 mDNS_Lock(m);
6266*4b22b933Srs200217 status = mDNS_Register_internal(m, rr);
6267*4b22b933Srs200217 mDNS_Unlock(m);
6268*4b22b933Srs200217 return(status);
6269*4b22b933Srs200217 }
6270*4b22b933Srs200217
mDNS_Update(mDNS * const m,AuthRecord * const rr,mDNSu32 newttl,const mDNSu16 newrdlength,RData * const newrdata,mDNSRecordUpdateCallback * Callback)6271*4b22b933Srs200217 mDNSexport mStatus mDNS_Update(mDNS *const m, AuthRecord *const rr, mDNSu32 newttl,
6272*4b22b933Srs200217 const mDNSu16 newrdlength, RData *const newrdata, mDNSRecordUpdateCallback *Callback)
6273*4b22b933Srs200217 {
6274*4b22b933Srs200217 #ifndef UNICAST_DISABLED
6275*4b22b933Srs200217 mDNSBool unicast = !(rr->resrec.InterfaceID == mDNSInterface_LocalOnly || IsLocalDomain(rr->resrec.name));
6276*4b22b933Srs200217 #else
6277*4b22b933Srs200217 mDNSBool unicast = mDNSfalse;
6278*4b22b933Srs200217 #endif
6279*4b22b933Srs200217
6280*4b22b933Srs200217 if (!ValidateRData(rr->resrec.rrtype, newrdlength, newrdata))
6281*4b22b933Srs200217 {
6282*4b22b933Srs200217 LogMsg("Attempt to update record with invalid rdata: %s", GetRRDisplayString_rdb(&rr->resrec, &newrdata->u, m->MsgBuffer));
6283*4b22b933Srs200217 return(mStatus_Invalid);
6284*4b22b933Srs200217 }
6285*4b22b933Srs200217
6286*4b22b933Srs200217 mDNS_Lock(m);
6287*4b22b933Srs200217
6288*4b22b933Srs200217 // If TTL is unspecified, leave TTL unchanged
6289*4b22b933Srs200217 if (newttl == 0) newttl = rr->resrec.rroriginalttl;
6290*4b22b933Srs200217
6291*4b22b933Srs200217 // If we already have an update queued up which has not gone through yet,
6292*4b22b933Srs200217 // give the client a chance to free that memory
6293*4b22b933Srs200217 if (!unicast && rr->NewRData)
6294*4b22b933Srs200217 {
6295*4b22b933Srs200217 RData *n = rr->NewRData;
6296*4b22b933Srs200217 rr->NewRData = mDNSNULL; // Clear the NewRData pointer ...
6297*4b22b933Srs200217 if (rr->UpdateCallback)
6298*4b22b933Srs200217 rr->UpdateCallback(m, rr, n); // ...and let the client free this memory, if necessary
6299*4b22b933Srs200217 }
6300*4b22b933Srs200217
6301*4b22b933Srs200217 rr->NewRData = newrdata;
6302*4b22b933Srs200217 rr->newrdlength = newrdlength;
6303*4b22b933Srs200217 rr->UpdateCallback = Callback;
6304*4b22b933Srs200217
6305*4b22b933Srs200217 if (unicast) { mStatus status = uDNS_UpdateRecord(m, rr); mDNS_Unlock(m); return(status); }
6306*4b22b933Srs200217
6307*4b22b933Srs200217 if (rr->resrec.rroriginalttl == newttl &&
6308*4b22b933Srs200217 rr->resrec.rdlength == newrdlength && mDNSPlatformMemSame(rr->resrec.rdata->u.data, newrdata->u.data, newrdlength))
6309*4b22b933Srs200217 CompleteRDataUpdate(m, rr);
6310*4b22b933Srs200217 else
6311*4b22b933Srs200217 {
6312*4b22b933Srs200217 domainlabel name;
6313*4b22b933Srs200217 domainname type, domain;
6314*4b22b933Srs200217 DeconstructServiceName(rr->resrec.name, &name, &type, &domain);
6315*4b22b933Srs200217 rr->AnnounceCount = InitialAnnounceCount;
6316*4b22b933Srs200217 // iChat often does suprious record updates where no data has changed. For the _presence service type, using
6317*4b22b933Srs200217 // name/value pairs, the mDNSPlatformMemSame() check above catches this and correctly suppresses the wasteful
6318*4b22b933Srs200217 // update. For the _ichat service type, the XML encoding introduces spurious noise differences into the data
6319*4b22b933Srs200217 // even though there's no actual semantic change, so the mDNSPlatformMemSame() check doesn't help us.
6320*4b22b933Srs200217 // To work around this, we simply unilaterally limit all legacy _ichat-type updates to a single announcement.
6321*4b22b933Srs200217 if (SameDomainLabel(type.c, (mDNSu8*)"\x6_ichat")) rr->AnnounceCount = 1;
6322*4b22b933Srs200217 rr->ThisAPInterval = DefaultAPIntervalForRecordType(rr->resrec.RecordType);
6323*4b22b933Srs200217 InitializeLastAPTime(m, rr);
6324*4b22b933Srs200217 while (rr->NextUpdateCredit && m->timenow - rr->NextUpdateCredit >= 0) GrantUpdateCredit(rr);
6325*4b22b933Srs200217 if (!rr->UpdateBlocked && rr->UpdateCredits) rr->UpdateCredits--;
6326*4b22b933Srs200217 if (!rr->NextUpdateCredit) rr->NextUpdateCredit = NonZeroTime(m->timenow + kUpdateCreditRefreshInterval);
6327*4b22b933Srs200217 if (rr->AnnounceCount > rr->UpdateCredits + 1) rr->AnnounceCount = (mDNSu8)(rr->UpdateCredits + 1);
6328*4b22b933Srs200217 if (rr->UpdateCredits <= 5)
6329*4b22b933Srs200217 {
6330*4b22b933Srs200217 mDNSu32 delay = 6 - rr->UpdateCredits; // Delay 1 second, then 2, then 3, etc. up to 6 seconds maximum
6331*4b22b933Srs200217 if (!rr->UpdateBlocked) rr->UpdateBlocked = NonZeroTime(m->timenow + (mDNSs32)delay * mDNSPlatformOneSecond);
6332*4b22b933Srs200217 rr->ThisAPInterval *= 4;
6333*4b22b933Srs200217 rr->LastAPTime = rr->UpdateBlocked - rr->ThisAPInterval;
6334*4b22b933Srs200217 LogMsg("Excessive update rate for %##s; delaying announcement by %ld second%s",
6335*4b22b933Srs200217 rr->resrec.name->c, delay, delay > 1 ? "s" : "");
6336*4b22b933Srs200217 }
6337*4b22b933Srs200217 rr->resrec.rroriginalttl = newttl;
6338*4b22b933Srs200217 }
6339*4b22b933Srs200217
6340*4b22b933Srs200217 mDNS_Unlock(m);
6341*4b22b933Srs200217 return(mStatus_NoError);
6342*4b22b933Srs200217 }
6343*4b22b933Srs200217
6344*4b22b933Srs200217 // NOTE: mDNS_Deregister calls mDNS_Deregister_internal which can call a user callback, which may change
6345*4b22b933Srs200217 // the record list and/or question list.
6346*4b22b933Srs200217 // Any code walking either list must use the CurrentQuestion and/or CurrentRecord mechanism to protect against this.
mDNS_Deregister(mDNS * const m,AuthRecord * const rr)6347*4b22b933Srs200217 mDNSexport mStatus mDNS_Deregister(mDNS *const m, AuthRecord *const rr)
6348*4b22b933Srs200217 {
6349*4b22b933Srs200217 mStatus status;
6350*4b22b933Srs200217 mDNS_Lock(m);
6351*4b22b933Srs200217 status = mDNS_Deregister_internal(m, rr, mDNS_Dereg_normal);
6352*4b22b933Srs200217 mDNS_Unlock(m);
6353*4b22b933Srs200217 return(status);
6354*4b22b933Srs200217 }
6355*4b22b933Srs200217
6356*4b22b933Srs200217 mDNSexport void mDNS_HostNameCallback(mDNS *const m, AuthRecord *const rr, mStatus result);
6357*4b22b933Srs200217
FindFirstAdvertisedInterface(mDNS * const m)6358*4b22b933Srs200217 mDNSlocal NetworkInterfaceInfo *FindFirstAdvertisedInterface(mDNS *const m)
6359*4b22b933Srs200217 {
6360*4b22b933Srs200217 NetworkInterfaceInfo *intf;
6361*4b22b933Srs200217 for (intf = m->HostInterfaces; intf; intf = intf->next)
6362*4b22b933Srs200217 if (intf->Advertise) break;
6363*4b22b933Srs200217 return(intf);
6364*4b22b933Srs200217 }
6365*4b22b933Srs200217
AdvertiseInterface(mDNS * const m,NetworkInterfaceInfo * set)6366*4b22b933Srs200217 mDNSlocal void AdvertiseInterface(mDNS *const m, NetworkInterfaceInfo *set)
6367*4b22b933Srs200217 {
6368*4b22b933Srs200217 char buffer[256];
6369*4b22b933Srs200217 NetworkInterfaceInfo *primary = FindFirstAdvertisedInterface(m);
6370*4b22b933Srs200217 if (!primary) primary = set; // If no existing advertised interface, this new NetworkInterfaceInfo becomes our new primary
6371*4b22b933Srs200217
6372*4b22b933Srs200217 // Send dynamic update for non-linklocal IPv4 Addresses
6373*4b22b933Srs200217 mDNS_SetupResourceRecord(&set->RR_A, mDNSNULL, set->InterfaceID, kDNSType_A, kHostNameTTL, kDNSRecordTypeUnique, mDNS_HostNameCallback, set);
6374*4b22b933Srs200217 mDNS_SetupResourceRecord(&set->RR_PTR, mDNSNULL, set->InterfaceID, kDNSType_PTR, kHostNameTTL, kDNSRecordTypeKnownUnique, mDNSNULL, mDNSNULL);
6375*4b22b933Srs200217 mDNS_SetupResourceRecord(&set->RR_HINFO, mDNSNULL, set->InterfaceID, kDNSType_HINFO, kHostNameTTL, kDNSRecordTypeUnique, mDNSNULL, mDNSNULL);
6376*4b22b933Srs200217
6377*4b22b933Srs200217 #if ANSWER_REMOTE_HOSTNAME_QUERIES
6378*4b22b933Srs200217 set->RR_A .AllowRemoteQuery = mDNStrue;
6379*4b22b933Srs200217 set->RR_PTR .AllowRemoteQuery = mDNStrue;
6380*4b22b933Srs200217 set->RR_HINFO.AllowRemoteQuery = mDNStrue;
6381*4b22b933Srs200217 #endif
6382*4b22b933Srs200217 // 1. Set up Address record to map from host name ("foo.local.") to IP address
6383*4b22b933Srs200217 // 2. Set up reverse-lookup PTR record to map from our address back to our host name
6384*4b22b933Srs200217 AssignDomainName(set->RR_A.resrec.name, &m->MulticastHostname);
6385*4b22b933Srs200217 if (set->ip.type == mDNSAddrType_IPv4)
6386*4b22b933Srs200217 {
6387*4b22b933Srs200217 set->RR_A.resrec.rrtype = kDNSType_A;
6388*4b22b933Srs200217 set->RR_A.resrec.rdata->u.ipv4 = set->ip.ip.v4;
6389*4b22b933Srs200217 // Note: This is reverse order compared to a normal dotted-decimal IP address
6390*4b22b933Srs200217 mDNS_snprintf(buffer, sizeof(buffer), "%d.%d.%d.%d.in-addr.arpa.",
6391*4b22b933Srs200217 set->ip.ip.v4.b[3], set->ip.ip.v4.b[2], set->ip.ip.v4.b[1], set->ip.ip.v4.b[0]);
6392*4b22b933Srs200217 }
6393*4b22b933Srs200217 else if (set->ip.type == mDNSAddrType_IPv6)
6394*4b22b933Srs200217 {
6395*4b22b933Srs200217 int i;
6396*4b22b933Srs200217 set->RR_A.resrec.rrtype = kDNSType_AAAA;
6397*4b22b933Srs200217 set->RR_A.resrec.rdata->u.ipv6 = set->ip.ip.v6;
6398*4b22b933Srs200217 for (i = 0; i < 16; i++)
6399*4b22b933Srs200217 {
6400*4b22b933Srs200217 static const char hexValues[] = "0123456789ABCDEF";
6401*4b22b933Srs200217 buffer[i * 4 ] = hexValues[set->ip.ip.v6.b[15 - i] & 0x0F];
6402*4b22b933Srs200217 buffer[i * 4 + 1] = '.';
6403*4b22b933Srs200217 buffer[i * 4 + 2] = hexValues[set->ip.ip.v6.b[15 - i] >> 4];
6404*4b22b933Srs200217 buffer[i * 4 + 3] = '.';
6405*4b22b933Srs200217 }
6406*4b22b933Srs200217 mDNS_snprintf(&buffer[64], sizeof(buffer)-64, "ip6.arpa.");
6407*4b22b933Srs200217 }
6408*4b22b933Srs200217
6409*4b22b933Srs200217 MakeDomainNameFromDNSNameString(set->RR_PTR.resrec.name, buffer);
6410*4b22b933Srs200217 set->RR_PTR.HostTarget = mDNStrue; // Tell mDNS that the target of this PTR is to be kept in sync with our host name
6411*4b22b933Srs200217 set->RR_PTR.ForceMCast = mDNStrue; // This PTR points to our dot-local name, so don't ever try to write it into a uDNS server
6412*4b22b933Srs200217
6413*4b22b933Srs200217 set->RR_A.RRSet = &primary->RR_A; // May refer to self
6414*4b22b933Srs200217
6415*4b22b933Srs200217 mDNS_Register_internal(m, &set->RR_A);
6416*4b22b933Srs200217 mDNS_Register_internal(m, &set->RR_PTR);
6417*4b22b933Srs200217
6418*4b22b933Srs200217 if (m->HIHardware.c[0] > 0 && m->HISoftware.c[0] > 0 && m->HIHardware.c[0] + m->HISoftware.c[0] <= 254)
6419*4b22b933Srs200217 {
6420*4b22b933Srs200217 mDNSu8 *p = set->RR_HINFO.resrec.rdata->u.data;
6421*4b22b933Srs200217 AssignDomainName(set->RR_HINFO.resrec.name, &m->MulticastHostname);
6422*4b22b933Srs200217 set->RR_HINFO.DependentOn = &set->RR_A;
6423*4b22b933Srs200217 mDNSPlatformMemCopy(&m->HIHardware, p, 1 + (mDNSu32)m->HIHardware.c[0]);
6424*4b22b933Srs200217 p += 1 + (int)p[0];
6425*4b22b933Srs200217 mDNSPlatformMemCopy(&m->HISoftware, p, 1 + (mDNSu32)m->HISoftware.c[0]);
6426*4b22b933Srs200217 mDNS_Register_internal(m, &set->RR_HINFO);
6427*4b22b933Srs200217 }
6428*4b22b933Srs200217 else
6429*4b22b933Srs200217 {
6430*4b22b933Srs200217 debugf("Not creating HINFO record: platform support layer provided no information");
6431*4b22b933Srs200217 set->RR_HINFO.resrec.RecordType = kDNSRecordTypeUnregistered;
6432*4b22b933Srs200217 }
6433*4b22b933Srs200217 }
6434*4b22b933Srs200217
DeadvertiseInterface(mDNS * const m,NetworkInterfaceInfo * set)6435*4b22b933Srs200217 mDNSlocal void DeadvertiseInterface(mDNS *const m, NetworkInterfaceInfo *set)
6436*4b22b933Srs200217 {
6437*4b22b933Srs200217 NetworkInterfaceInfo *intf;
6438*4b22b933Srs200217
6439*4b22b933Srs200217 // If we still have address records referring to this one, update them
6440*4b22b933Srs200217 NetworkInterfaceInfo *primary = FindFirstAdvertisedInterface(m);
6441*4b22b933Srs200217 AuthRecord *A = primary ? &primary->RR_A : mDNSNULL;
6442*4b22b933Srs200217 for (intf = m->HostInterfaces; intf; intf = intf->next)
6443*4b22b933Srs200217 if (intf->RR_A.RRSet == &set->RR_A)
6444*4b22b933Srs200217 intf->RR_A.RRSet = A;
6445*4b22b933Srs200217
6446*4b22b933Srs200217 // Unregister these records.
6447*4b22b933Srs200217 // When doing the mDNS_Close processing, we first call DeadvertiseInterface for each interface, so by the time the platform
6448*4b22b933Srs200217 // support layer gets to call mDNS_DeregisterInterface, the address and PTR records have already been deregistered for it.
6449*4b22b933Srs200217 // Also, in the event of a name conflict, one or more of our records will have been forcibly deregistered.
6450*4b22b933Srs200217 // To avoid unnecessary and misleading warning messages, we check the RecordType before calling mDNS_Deregister_internal().
6451*4b22b933Srs200217 if (set->RR_A. resrec.RecordType) mDNS_Deregister_internal(m, &set->RR_A, mDNS_Dereg_normal);
6452*4b22b933Srs200217 if (set->RR_PTR. resrec.RecordType) mDNS_Deregister_internal(m, &set->RR_PTR, mDNS_Dereg_normal);
6453*4b22b933Srs200217 if (set->RR_HINFO.resrec.RecordType) mDNS_Deregister_internal(m, &set->RR_HINFO, mDNS_Dereg_normal);
6454*4b22b933Srs200217 }
6455*4b22b933Srs200217
mDNS_SetFQDN(mDNS * const m)6456*4b22b933Srs200217 mDNSexport void mDNS_SetFQDN(mDNS *const m)
6457*4b22b933Srs200217 {
6458*4b22b933Srs200217 domainname newmname;
6459*4b22b933Srs200217 NetworkInterfaceInfo *intf;
6460*4b22b933Srs200217 AuthRecord *rr;
6461*4b22b933Srs200217 newmname.c[0] = 0;
6462*4b22b933Srs200217
6463*4b22b933Srs200217 if (!AppendDomainLabel(&newmname, &m->hostlabel)) { LogMsg("ERROR: mDNS_SetFQDN: Cannot create MulticastHostname"); return; }
6464*4b22b933Srs200217 if (!AppendLiteralLabelString(&newmname, "local")) { LogMsg("ERROR: mDNS_SetFQDN: Cannot create MulticastHostname"); return; }
6465*4b22b933Srs200217 if (SameDomainName(&m->MulticastHostname, &newmname)) { LogMsg("mDNS_SetFQDN - hostname unchanged"); return; }
6466*4b22b933Srs200217
6467*4b22b933Srs200217 mDNS_Lock(m);
6468*4b22b933Srs200217 AssignDomainName(&m->MulticastHostname, &newmname);
6469*4b22b933Srs200217
6470*4b22b933Srs200217 // 1. Stop advertising our address records on all interfaces
6471*4b22b933Srs200217 for (intf = m->HostInterfaces; intf; intf = intf->next)
6472*4b22b933Srs200217 if (intf->Advertise) DeadvertiseInterface(m, intf);
6473*4b22b933Srs200217
6474*4b22b933Srs200217 // 2. Start advertising our address records using the new name
6475*4b22b933Srs200217 for (intf = m->HostInterfaces; intf; intf = intf->next)
6476*4b22b933Srs200217 if (intf->Advertise) AdvertiseInterface(m, intf);
6477*4b22b933Srs200217
6478*4b22b933Srs200217 // 3. Make sure that any SRV records (and the like) that reference our
6479*4b22b933Srs200217 // host name in their rdata get updated to reference this new host name
6480*4b22b933Srs200217 for (rr = m->ResourceRecords; rr; rr=rr->next) if (rr->HostTarget) SetTargetToHostName(m, rr);
6481*4b22b933Srs200217 for (rr = m->DuplicateRecords; rr; rr=rr->next) if (rr->HostTarget) SetTargetToHostName(m, rr);
6482*4b22b933Srs200217
6483*4b22b933Srs200217 mDNS_Unlock(m);
6484*4b22b933Srs200217 }
6485*4b22b933Srs200217
mDNS_HostNameCallback(mDNS * const m,AuthRecord * const rr,mStatus result)6486*4b22b933Srs200217 mDNSexport void mDNS_HostNameCallback(mDNS *const m, AuthRecord *const rr, mStatus result)
6487*4b22b933Srs200217 {
6488*4b22b933Srs200217 (void)rr; // Unused parameter
6489*4b22b933Srs200217
6490*4b22b933Srs200217 #if MDNS_DEBUGMSGS
6491*4b22b933Srs200217 {
6492*4b22b933Srs200217 char *msg = "Unknown result";
6493*4b22b933Srs200217 if (result == mStatus_NoError) msg = "Name registered";
6494*4b22b933Srs200217 else if (result == mStatus_NameConflict) msg = "Name conflict";
6495*4b22b933Srs200217 debugf("mDNS_HostNameCallback: %##s (%s) %s (%ld)", rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype), msg, result);
6496*4b22b933Srs200217 }
6497*4b22b933Srs200217 #endif
6498*4b22b933Srs200217
6499*4b22b933Srs200217 if (result == mStatus_NoError)
6500*4b22b933Srs200217 {
6501*4b22b933Srs200217 // Notify the client that the host name is successfully registered
6502*4b22b933Srs200217 if (m->MainCallback)
6503*4b22b933Srs200217 {
6504*4b22b933Srs200217 m->mDNS_reentrancy++; // Increment to allow client to legally make mDNS API calls from the callback
6505*4b22b933Srs200217 m->MainCallback(m, result);
6506*4b22b933Srs200217 m->mDNS_reentrancy--; // Decrement to block mDNS API calls again
6507*4b22b933Srs200217 }
6508*4b22b933Srs200217 }
6509*4b22b933Srs200217 else if (result == mStatus_NameConflict)
6510*4b22b933Srs200217 {
6511*4b22b933Srs200217 domainlabel oldlabel = m->hostlabel;
6512*4b22b933Srs200217
6513*4b22b933Srs200217 // 1. First give the client callback a chance to pick a new name
6514*4b22b933Srs200217 if (m->MainCallback)
6515*4b22b933Srs200217 {
6516*4b22b933Srs200217 m->mDNS_reentrancy++; // Increment to allow client to legally make mDNS API calls from the callback
6517*4b22b933Srs200217 m->MainCallback(m, mStatus_NameConflict);
6518*4b22b933Srs200217 m->mDNS_reentrancy--; // Decrement to block mDNS API calls again
6519*4b22b933Srs200217 }
6520*4b22b933Srs200217
6521*4b22b933Srs200217 // 2. If the client callback didn't do it, add (or increment) an index ourselves
6522*4b22b933Srs200217 if (SameDomainLabel(m->hostlabel.c, oldlabel.c))
6523*4b22b933Srs200217 IncrementLabelSuffix(&m->hostlabel, mDNSfalse);
6524*4b22b933Srs200217
6525*4b22b933Srs200217 // 3. Generate the FQDNs from the hostlabel,
6526*4b22b933Srs200217 // and make sure all SRV records, etc., are updated to reference our new hostname
6527*4b22b933Srs200217 mDNS_SetFQDN(m);
6528*4b22b933Srs200217 LogMsg("Local Hostname %#s.local already in use; will try %#s.local instead", oldlabel.c, m->hostlabel.c);
6529*4b22b933Srs200217 }
6530*4b22b933Srs200217 else if (result == mStatus_MemFree)
6531*4b22b933Srs200217 {
6532*4b22b933Srs200217 // .local hostnames do not require goodbyes - we ignore the MemFree (which is sent directly by
6533*4b22b933Srs200217 // mDNS_Deregister_internal), and allow the caller to deallocate immediately following mDNS_DeadvertiseInterface
6534*4b22b933Srs200217 debugf("mDNS_HostNameCallback: MemFree (ignored)");
6535*4b22b933Srs200217 }
6536*4b22b933Srs200217 else
6537*4b22b933Srs200217 LogMsg("mDNS_HostNameCallback: Unknown error %ld for registration of record %s", result, rr->resrec.name->c);
6538*4b22b933Srs200217 }
6539*4b22b933Srs200217
UpdateInterfaceProtocols(mDNS * const m,NetworkInterfaceInfo * active)6540*4b22b933Srs200217 mDNSlocal void UpdateInterfaceProtocols(mDNS *const m, NetworkInterfaceInfo *active)
6541*4b22b933Srs200217 {
6542*4b22b933Srs200217 NetworkInterfaceInfo *intf;
6543*4b22b933Srs200217 active->IPv4Available = mDNSfalse;
6544*4b22b933Srs200217 active->IPv6Available = mDNSfalse;
6545*4b22b933Srs200217 for (intf = m->HostInterfaces; intf; intf = intf->next)
6546*4b22b933Srs200217 if (intf->InterfaceID == active->InterfaceID)
6547*4b22b933Srs200217 {
6548*4b22b933Srs200217 if (intf->ip.type == mDNSAddrType_IPv4 && intf->McastTxRx) active->IPv4Available = mDNStrue;
6549*4b22b933Srs200217 if (intf->ip.type == mDNSAddrType_IPv6 && intf->McastTxRx) active->IPv6Available = mDNStrue;
6550*4b22b933Srs200217 }
6551*4b22b933Srs200217 }
6552*4b22b933Srs200217
mDNS_RegisterInterface(mDNS * const m,NetworkInterfaceInfo * set,mDNSBool flapping)6553*4b22b933Srs200217 mDNSexport mStatus mDNS_RegisterInterface(mDNS *const m, NetworkInterfaceInfo *set, mDNSBool flapping)
6554*4b22b933Srs200217 {
6555*4b22b933Srs200217 mDNSBool FirstOfType = mDNStrue;
6556*4b22b933Srs200217 NetworkInterfaceInfo **p = &m->HostInterfaces;
6557*4b22b933Srs200217
6558*4b22b933Srs200217 if (!set->InterfaceID)
6559*4b22b933Srs200217 { LogMsg("Error! Tried to register a NetworkInterfaceInfo %#a with zero InterfaceID", &set->ip); return(mStatus_Invalid); }
6560*4b22b933Srs200217
6561*4b22b933Srs200217 if (!mDNSAddressIsValidNonZero(&set->mask))
6562*4b22b933Srs200217 { LogMsg("Error! Tried to register a NetworkInterfaceInfo %#a with invalid mask %#a", &set->ip, &set->mask); return(mStatus_Invalid); }
6563*4b22b933Srs200217
6564*4b22b933Srs200217 mDNS_Lock(m);
6565*4b22b933Srs200217
6566*4b22b933Srs200217 // Assume this interface will be active now, unless we find a duplicate already in the list
6567*4b22b933Srs200217 set->InterfaceActive = mDNStrue;
6568*4b22b933Srs200217 set->IPv4Available = (set->ip.type == mDNSAddrType_IPv4 && set->McastTxRx);
6569*4b22b933Srs200217 set->IPv6Available = (set->ip.type == mDNSAddrType_IPv6 && set->McastTxRx);
6570*4b22b933Srs200217
6571*4b22b933Srs200217 // Scan list to see if this InterfaceID is already represented
6572*4b22b933Srs200217 while (*p)
6573*4b22b933Srs200217 {
6574*4b22b933Srs200217 if (*p == set)
6575*4b22b933Srs200217 {
6576*4b22b933Srs200217 LogMsg("Error! Tried to register a NetworkInterfaceInfo that's already in the list");
6577*4b22b933Srs200217 mDNS_Unlock(m);
6578*4b22b933Srs200217 return(mStatus_AlreadyRegistered);
6579*4b22b933Srs200217 }
6580*4b22b933Srs200217
6581*4b22b933Srs200217 if ((*p)->InterfaceID == set->InterfaceID)
6582*4b22b933Srs200217 {
6583*4b22b933Srs200217 // This InterfaceID already represented by a different interface in the list, so mark this instance inactive for now
6584*4b22b933Srs200217 set->InterfaceActive = mDNSfalse;
6585*4b22b933Srs200217 if (set->ip.type == (*p)->ip.type) FirstOfType = mDNSfalse;
6586*4b22b933Srs200217 if (set->ip.type == mDNSAddrType_IPv4 && set->McastTxRx) (*p)->IPv4Available = mDNStrue;
6587*4b22b933Srs200217 if (set->ip.type == mDNSAddrType_IPv6 && set->McastTxRx) (*p)->IPv6Available = mDNStrue;
6588*4b22b933Srs200217 }
6589*4b22b933Srs200217
6590*4b22b933Srs200217 p=&(*p)->next;
6591*4b22b933Srs200217 }
6592*4b22b933Srs200217
6593*4b22b933Srs200217 set->next = mDNSNULL;
6594*4b22b933Srs200217 *p = set;
6595*4b22b933Srs200217
6596*4b22b933Srs200217 if (set->Advertise)
6597*4b22b933Srs200217 AdvertiseInterface(m, set);
6598*4b22b933Srs200217
6599*4b22b933Srs200217 LogOperation("mDNS_RegisterInterface: InterfaceID %p %s (%#a) %s", set->InterfaceID, set->ifname, &set->ip,
6600*4b22b933Srs200217 set->InterfaceActive ?
6601*4b22b933Srs200217 "not represented in list; marking active and retriggering queries" :
6602*4b22b933Srs200217 "already represented in list; marking inactive for now");
6603*4b22b933Srs200217
6604*4b22b933Srs200217 // In early versions of OS X the IPv6 address remains on an interface even when the interface is turned off,
6605*4b22b933Srs200217 // giving the false impression that there's an active representative of this interface when there really isn't.
6606*4b22b933Srs200217 // Therefore, when registering an interface, we want to re-trigger our questions and re-probe our Resource Records,
6607*4b22b933Srs200217 // even if we believe that we previously had an active representative of this interface.
6608*4b22b933Srs200217 if (set->McastTxRx && ((m->KnownBugs & mDNS_KnownBug_PhantomInterfaces) || FirstOfType || set->InterfaceActive))
6609*4b22b933Srs200217 {
6610*4b22b933Srs200217 DNSQuestion *q;
6611*4b22b933Srs200217 AuthRecord *rr;
6612*4b22b933Srs200217 // If flapping, delay between first and second queries is eight seconds instead of one
6613*4b22b933Srs200217 mDNSs32 delay = flapping ? mDNSPlatformOneSecond * 5 : 0;
6614*4b22b933Srs200217 mDNSu8 announce = flapping ? (mDNSu8)1 : InitialAnnounceCount;
6615*4b22b933Srs200217
6616*4b22b933Srs200217 // Use a small amount of randomness:
6617*4b22b933Srs200217 // In the case of a network administrator turning on an Ethernet hub so that all the
6618*4b22b933Srs200217 // connected machines establish link at exactly the same time, we don't want them all
6619*4b22b933Srs200217 // to go and hit the network with identical queries at exactly the same moment.
6620*4b22b933Srs200217 if (!m->SuppressSending) m->SuppressSending = m->timenow + (mDNSs32)mDNSRandom((mDNSu32)InitialQuestionInterval);
6621*4b22b933Srs200217
6622*4b22b933Srs200217 if (flapping)
6623*4b22b933Srs200217 {
6624*4b22b933Srs200217 LogMsg("Note: Frequent transitions for interface %s (%#a); network traffic reduction measures in effect", set->ifname, &set->ip);
6625*4b22b933Srs200217 if (!m->SuppressProbes ||
6626*4b22b933Srs200217 m->SuppressProbes - (m->timenow + delay) < 0)
6627*4b22b933Srs200217 m->SuppressProbes = (m->timenow + delay);
6628*4b22b933Srs200217 }
6629*4b22b933Srs200217
6630*4b22b933Srs200217 for (q = m->Questions; q; q=q->next) // Scan our list of questions
6631*4b22b933Srs200217 if (!q->InterfaceID || q->InterfaceID == set->InterfaceID) // If non-specific Q, or Q on this specific interface,
6632*4b22b933Srs200217 { // then reactivate this question
6633*4b22b933Srs200217 mDNSs32 initial = (flapping && q->FlappingInterface != set->InterfaceID) ? InitialQuestionInterval * 8 : InitialQuestionInterval;
6634*4b22b933Srs200217 mDNSs32 qdelay = (flapping && q->FlappingInterface != set->InterfaceID) ? mDNSPlatformOneSecond * 5 : 0;
6635*4b22b933Srs200217 if (flapping && q->FlappingInterface == set->InterfaceID)
6636*4b22b933Srs200217 LogOperation("No cache records for %##s (%s) expired; no need for immediate question", q->qname.c, DNSTypeName(q->qtype));
6637*4b22b933Srs200217
6638*4b22b933Srs200217 if (!q->ThisQInterval || q->ThisQInterval > initial)
6639*4b22b933Srs200217 {
6640*4b22b933Srs200217 q->ThisQInterval = initial;
6641*4b22b933Srs200217 q->RequestUnicast = 2; // Set to 2 because is decremented once *before* we check it
6642*4b22b933Srs200217 }
6643*4b22b933Srs200217 if (q->LastQTime - (m->timenow - q->ThisQInterval + qdelay) > 0)
6644*4b22b933Srs200217 q->LastQTime = (m->timenow - q->ThisQInterval + qdelay);
6645*4b22b933Srs200217 q->RecentAnswerPkts = 0;
6646*4b22b933Srs200217 SetNextQueryTime(m,q);
6647*4b22b933Srs200217 }
6648*4b22b933Srs200217
6649*4b22b933Srs200217 // For all our non-specific authoritative resource records (and any dormant records specific to this interface)
6650*4b22b933Srs200217 // we now need them to re-probe if necessary, and then re-announce.
6651*4b22b933Srs200217 for (rr = m->ResourceRecords; rr; rr=rr->next)
6652*4b22b933Srs200217 if (!rr->resrec.InterfaceID || rr->resrec.InterfaceID == set->InterfaceID)
6653*4b22b933Srs200217 {
6654*4b22b933Srs200217 if (rr->resrec.RecordType == kDNSRecordTypeVerified && !rr->DependentOn) rr->resrec.RecordType = kDNSRecordTypeUnique;
6655*4b22b933Srs200217 rr->ProbeCount = DefaultProbeCountForRecordType(rr->resrec.RecordType);
6656*4b22b933Srs200217 if (rr->AnnounceCount < announce) rr->AnnounceCount = announce;
6657*4b22b933Srs200217 rr->ThisAPInterval = DefaultAPIntervalForRecordType(rr->resrec.RecordType);
6658*4b22b933Srs200217 InitializeLastAPTime(m, rr);
6659*4b22b933Srs200217 }
6660*4b22b933Srs200217 }
6661*4b22b933Srs200217
6662*4b22b933Srs200217 mDNS_Unlock(m);
6663*4b22b933Srs200217 return(mStatus_NoError);
6664*4b22b933Srs200217 }
6665*4b22b933Srs200217
6666*4b22b933Srs200217 // NOTE: mDNS_DeregisterInterface calls mDNS_Deregister_internal which can call a user callback, which may change
6667*4b22b933Srs200217 // the record list and/or question list.
6668*4b22b933Srs200217 // Any code walking either list must use the CurrentQuestion and/or CurrentRecord mechanism to protect against this.
mDNS_DeregisterInterface(mDNS * const m,NetworkInterfaceInfo * set,mDNSBool flapping)6669*4b22b933Srs200217 mDNSexport void mDNS_DeregisterInterface(mDNS *const m, NetworkInterfaceInfo *set, mDNSBool flapping)
6670*4b22b933Srs200217 {
6671*4b22b933Srs200217 NetworkInterfaceInfo **p = &m->HostInterfaces;
6672*4b22b933Srs200217
6673*4b22b933Srs200217 mDNSBool revalidate = mDNSfalse;
6674*4b22b933Srs200217 // If this platform has the "phantom interfaces" known bug (e.g. Jaguar), we have to revalidate records every
6675*4b22b933Srs200217 // time an interface goes away. Otherwise, when you disconnect the Ethernet cable, the system reports that it
6676*4b22b933Srs200217 // still has an IPv6 address, and if we don't revalidate those records don't get deleted in a timely fashion.
6677*4b22b933Srs200217 if (m->KnownBugs & mDNS_KnownBug_PhantomInterfaces) revalidate = mDNStrue;
6678*4b22b933Srs200217
6679*4b22b933Srs200217 mDNS_Lock(m);
6680*4b22b933Srs200217
6681*4b22b933Srs200217 // Find this record in our list
6682*4b22b933Srs200217 while (*p && *p != set) p=&(*p)->next;
6683*4b22b933Srs200217 if (!*p) { debugf("mDNS_DeregisterInterface: NetworkInterfaceInfo not found in list"); mDNS_Unlock(m); return; }
6684*4b22b933Srs200217
6685*4b22b933Srs200217 // Unlink this record from our list
6686*4b22b933Srs200217 *p = (*p)->next;
6687*4b22b933Srs200217 set->next = mDNSNULL;
6688*4b22b933Srs200217
6689*4b22b933Srs200217 if (!set->InterfaceActive)
6690*4b22b933Srs200217 {
6691*4b22b933Srs200217 // If this interface not the active member of its set, update the v4/v6Available flags for the active member
6692*4b22b933Srs200217 NetworkInterfaceInfo *intf;
6693*4b22b933Srs200217 for (intf = m->HostInterfaces; intf; intf = intf->next)
6694*4b22b933Srs200217 if (intf->InterfaceActive && intf->InterfaceID == set->InterfaceID)
6695*4b22b933Srs200217 UpdateInterfaceProtocols(m, intf);
6696*4b22b933Srs200217 }
6697*4b22b933Srs200217 else
6698*4b22b933Srs200217 {
6699*4b22b933Srs200217 NetworkInterfaceInfo *intf;
6700*4b22b933Srs200217 for (intf = m->HostInterfaces; intf; intf = intf->next)
6701*4b22b933Srs200217 if (intf->InterfaceID == set->InterfaceID)
6702*4b22b933Srs200217 break;
6703*4b22b933Srs200217 if (intf)
6704*4b22b933Srs200217 {
6705*4b22b933Srs200217 LogOperation("mDNS_DeregisterInterface: Another representative of InterfaceID %p %s (%#a) exists;"
6706*4b22b933Srs200217 " making it active", set->InterfaceID, set->ifname, &set->ip);
6707*4b22b933Srs200217 intf->InterfaceActive = mDNStrue;
6708*4b22b933Srs200217 UpdateInterfaceProtocols(m, intf);
6709*4b22b933Srs200217
6710*4b22b933Srs200217 // See if another representative *of the same type* exists. If not, we mave have gone from
6711*4b22b933Srs200217 // dual-stack to v6-only (or v4-only) so we need to reconfirm which records are still valid.
6712*4b22b933Srs200217 for (intf = m->HostInterfaces; intf; intf = intf->next)
6713*4b22b933Srs200217 if (intf->InterfaceID == set->InterfaceID && intf->ip.type == set->ip.type)
6714*4b22b933Srs200217 break;
6715*4b22b933Srs200217 if (!intf) revalidate = mDNStrue;
6716*4b22b933Srs200217 }
6717*4b22b933Srs200217 else
6718*4b22b933Srs200217 {
6719*4b22b933Srs200217 mDNSu32 slot;
6720*4b22b933Srs200217 CacheGroup *cg;
6721*4b22b933Srs200217 CacheRecord *rr;
6722*4b22b933Srs200217 DNSQuestion *q;
6723*4b22b933Srs200217 LogOperation("mDNS_DeregisterInterface: Last representative of InterfaceID %p %s (%#a) deregistered;"
6724*4b22b933Srs200217 " marking questions etc. dormant", set->InterfaceID, set->ifname, &set->ip);
6725*4b22b933Srs200217
6726*4b22b933Srs200217 if (flapping)
6727*4b22b933Srs200217 LogMsg("Note: Frequent transitions for interface %s (%#a); network traffic reduction measures in effect",
6728*4b22b933Srs200217 set->ifname, &set->ip);
6729*4b22b933Srs200217
6730*4b22b933Srs200217 // 1. Deactivate any questions specific to this interface, and tag appropriate questions
6731*4b22b933Srs200217 // so that mDNS_RegisterInterface() knows how swiftly it needs to reactivate them
6732*4b22b933Srs200217 for (q = m->Questions; q; q=q->next)
6733*4b22b933Srs200217 {
6734*4b22b933Srs200217 if (q->InterfaceID == set->InterfaceID) q->ThisQInterval = 0;
6735*4b22b933Srs200217 if (!q->InterfaceID || q->InterfaceID == set->InterfaceID)
6736*4b22b933Srs200217 q->FlappingInterface = set->InterfaceID;
6737*4b22b933Srs200217 }
6738*4b22b933Srs200217
6739*4b22b933Srs200217 // 2. Flush any cache records received on this interface
6740*4b22b933Srs200217 revalidate = mDNSfalse; // Don't revalidate if we're flushing the records
6741*4b22b933Srs200217 FORALL_CACHERECORDS(slot, cg, rr)
6742*4b22b933Srs200217 if (rr->resrec.InterfaceID == set->InterfaceID)
6743*4b22b933Srs200217 {
6744*4b22b933Srs200217 // If this interface is deemed flapping,
6745*4b22b933Srs200217 // postpone deleting the cache records in case the interface comes back again
6746*4b22b933Srs200217 if (!flapping) PurgeCacheResourceRecord(m, rr);
6747*4b22b933Srs200217 else mDNS_Reconfirm_internal(m, rr, kDefaultReconfirmTimeForFlappingInterface);
6748*4b22b933Srs200217 }
6749*4b22b933Srs200217 }
6750*4b22b933Srs200217 }
6751*4b22b933Srs200217
6752*4b22b933Srs200217 // If we were advertising on this interface, deregister those address and reverse-lookup records now
6753*4b22b933Srs200217 if (set->Advertise) DeadvertiseInterface(m, set);
6754*4b22b933Srs200217
6755*4b22b933Srs200217 // If we have any cache records received on this interface that went away, then re-verify them.
6756*4b22b933Srs200217 // In some versions of OS X the IPv6 address remains on an interface even when the interface is turned off,
6757*4b22b933Srs200217 // giving the false impression that there's an active representative of this interface when there really isn't.
6758*4b22b933Srs200217 // Don't need to do this when shutting down, because *all* interfaces are about to go away
6759*4b22b933Srs200217 if (revalidate && !m->mDNS_shutdown)
6760*4b22b933Srs200217 {
6761*4b22b933Srs200217 mDNSu32 slot;
6762*4b22b933Srs200217 CacheGroup *cg;
6763*4b22b933Srs200217 CacheRecord *rr;
6764*4b22b933Srs200217 m->NextCacheCheck = m->timenow;
6765*4b22b933Srs200217 FORALL_CACHERECORDS(slot, cg, rr)
6766*4b22b933Srs200217 if (rr->resrec.InterfaceID == set->InterfaceID)
6767*4b22b933Srs200217 mDNS_Reconfirm_internal(m, rr, kDefaultReconfirmTimeForFlappingInterface);
6768*4b22b933Srs200217 }
6769*4b22b933Srs200217
6770*4b22b933Srs200217 mDNS_Unlock(m);
6771*4b22b933Srs200217 }
6772*4b22b933Srs200217
ServiceCallback(mDNS * const m,AuthRecord * const rr,mStatus result)6773*4b22b933Srs200217 mDNSlocal void ServiceCallback(mDNS *const m, AuthRecord *const rr, mStatus result)
6774*4b22b933Srs200217 {
6775*4b22b933Srs200217 ServiceRecordSet *sr = (ServiceRecordSet *)rr->RecordContext;
6776*4b22b933Srs200217 (void)m; // Unused parameter
6777*4b22b933Srs200217
6778*4b22b933Srs200217 #if MDNS_DEBUGMSGS
6779*4b22b933Srs200217 {
6780*4b22b933Srs200217 char *msg = "Unknown result";
6781*4b22b933Srs200217 if (result == mStatus_NoError) msg = "Name Registered";
6782*4b22b933Srs200217 else if (result == mStatus_NameConflict) msg = "Name Conflict";
6783*4b22b933Srs200217 else if (result == mStatus_MemFree) msg = "Memory Free";
6784*4b22b933Srs200217 debugf("ServiceCallback: %##s (%s) %s (%ld)", rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype), msg, result);
6785*4b22b933Srs200217 }
6786*4b22b933Srs200217 #endif
6787*4b22b933Srs200217
6788*4b22b933Srs200217 // Only pass on the NoError acknowledgement for the SRV record (when it finishes probing)
6789*4b22b933Srs200217 if (result == mStatus_NoError && rr != &sr->RR_SRV) return;
6790*4b22b933Srs200217
6791*4b22b933Srs200217 // If we got a name conflict on either SRV or TXT, forcibly deregister this service, and record that we did that
6792*4b22b933Srs200217 if (result == mStatus_NameConflict)
6793*4b22b933Srs200217 {
6794*4b22b933Srs200217 sr->Conflict = mDNStrue; // Record that this service set had a conflict
6795*4b22b933Srs200217 mDNS_DeregisterService(m, sr); // Unlink the records from our list
6796*4b22b933Srs200217 return;
6797*4b22b933Srs200217 }
6798*4b22b933Srs200217
6799*4b22b933Srs200217 if (result == mStatus_MemFree)
6800*4b22b933Srs200217 {
6801*4b22b933Srs200217 // If the PTR record or any of the subtype PTR records are still in the process of deregistering,
6802*4b22b933Srs200217 // don't pass on the NameConflict/MemFree message until every record is finished cleaning up.
6803*4b22b933Srs200217 mDNSu32 i;
6804*4b22b933Srs200217 if (sr->RR_PTR.resrec.RecordType != kDNSRecordTypeUnregistered) return;
6805*4b22b933Srs200217 for (i=0; i<sr->NumSubTypes; i++) if (sr->SubTypes[i].resrec.RecordType != kDNSRecordTypeUnregistered) return;
6806*4b22b933Srs200217
6807*4b22b933Srs200217 // If this ServiceRecordSet was forcibly deregistered, and now its memory is ready for reuse,
6808*4b22b933Srs200217 // then we can now report the NameConflict to the client
6809*4b22b933Srs200217 if (sr->Conflict) result = mStatus_NameConflict;
6810*4b22b933Srs200217 }
6811*4b22b933Srs200217
6812*4b22b933Srs200217 // CAUTION: MUST NOT do anything more with sr after calling sr->Callback(), because the client's callback
6813*4b22b933Srs200217 // function is allowed to do anything, including deregistering this service and freeing its memory.
6814*4b22b933Srs200217 if (sr->ServiceCallback)
6815*4b22b933Srs200217 sr->ServiceCallback(m, sr, result);
6816*4b22b933Srs200217 }
6817*4b22b933Srs200217
NSSCallback(mDNS * const m,AuthRecord * const rr,mStatus result)6818*4b22b933Srs200217 mDNSlocal void NSSCallback(mDNS *const m, AuthRecord *const rr, mStatus result)
6819*4b22b933Srs200217 {
6820*4b22b933Srs200217 ServiceRecordSet *sr = (ServiceRecordSet *)rr->RecordContext;
6821*4b22b933Srs200217 if (sr->ServiceCallback)
6822*4b22b933Srs200217 sr->ServiceCallback(m, sr, result);
6823*4b22b933Srs200217 }
6824*4b22b933Srs200217
6825*4b22b933Srs200217 // Note:
6826*4b22b933Srs200217 // Name is first label of domain name (any dots in the name are actual dots, not label separators)
6827*4b22b933Srs200217 // Type is service type (e.g. "_ipp._tcp.")
6828*4b22b933Srs200217 // Domain is fully qualified domain name (i.e. ending with a null label)
6829*4b22b933Srs200217 // We always register a TXT, even if it is empty (so that clients are not
6830*4b22b933Srs200217 // left waiting forever looking for a nonexistent record.)
6831*4b22b933Srs200217 // If the host parameter is mDNSNULL or the root domain (ASCII NUL),
6832*4b22b933Srs200217 // then the default host name (m->MulticastHostname) is automatically used
mDNS_RegisterService(mDNS * const m,ServiceRecordSet * sr,const domainlabel * const name,const domainname * const type,const domainname * const domain,const domainname * const host,mDNSIPPort port,const mDNSu8 txtinfo[],mDNSu16 txtlen,AuthRecord * SubTypes,mDNSu32 NumSubTypes,const mDNSInterfaceID InterfaceID,mDNSServiceCallback Callback,void * Context)6833*4b22b933Srs200217 mDNSexport mStatus mDNS_RegisterService(mDNS *const m, ServiceRecordSet *sr,
6834*4b22b933Srs200217 const domainlabel *const name, const domainname *const type, const domainname *const domain,
6835*4b22b933Srs200217 const domainname *const host, mDNSIPPort port, const mDNSu8 txtinfo[], mDNSu16 txtlen,
6836*4b22b933Srs200217 AuthRecord *SubTypes, mDNSu32 NumSubTypes,
6837*4b22b933Srs200217 const mDNSInterfaceID InterfaceID, mDNSServiceCallback Callback, void *Context)
6838*4b22b933Srs200217 {
6839*4b22b933Srs200217 mStatus err;
6840*4b22b933Srs200217 mDNSu32 i;
6841*4b22b933Srs200217
6842*4b22b933Srs200217 sr->ServiceCallback = Callback;
6843*4b22b933Srs200217 sr->ServiceContext = Context;
6844*4b22b933Srs200217 sr->Extras = mDNSNULL;
6845*4b22b933Srs200217 sr->NumSubTypes = NumSubTypes;
6846*4b22b933Srs200217 sr->SubTypes = SubTypes;
6847*4b22b933Srs200217 sr->Conflict = mDNSfalse;
6848*4b22b933Srs200217 if (host && host->c[0]) sr->Host = *host;
6849*4b22b933Srs200217 else sr->Host.c[0] = 0;
6850*4b22b933Srs200217
6851*4b22b933Srs200217 // If port number is zero, that means the client is really trying to do a RegisterNoSuchService
6852*4b22b933Srs200217 if (!port.NotAnInteger)
6853*4b22b933Srs200217 return(mDNS_RegisterNoSuchService(m, &sr->RR_SRV, name, type, domain, mDNSNULL, mDNSInterface_Any, NSSCallback, sr));
6854*4b22b933Srs200217
6855*4b22b933Srs200217 // Initialize the AuthRecord objects to sane values
6856*4b22b933Srs200217 mDNS_SetupResourceRecord(&sr->RR_ADV, mDNSNULL, InterfaceID, kDNSType_PTR, kStandardTTL, kDNSRecordTypeAdvisory, ServiceCallback, sr);
6857*4b22b933Srs200217 mDNS_SetupResourceRecord(&sr->RR_PTR, mDNSNULL, InterfaceID, kDNSType_PTR, kStandardTTL, kDNSRecordTypeShared, ServiceCallback, sr);
6858*4b22b933Srs200217 mDNS_SetupResourceRecord(&sr->RR_SRV, mDNSNULL, InterfaceID, kDNSType_SRV, kHostNameTTL, kDNSRecordTypeUnique, ServiceCallback, sr);
6859*4b22b933Srs200217 mDNS_SetupResourceRecord(&sr->RR_TXT, mDNSNULL, InterfaceID, kDNSType_TXT, kStandardTTL, kDNSRecordTypeUnique, ServiceCallback, sr);
6860*4b22b933Srs200217
6861*4b22b933Srs200217 // If the client is registering an oversized TXT record,
6862*4b22b933Srs200217 // it is the client's responsibility to alloate a ServiceRecordSet structure that is large enough for it
6863*4b22b933Srs200217 if (sr->RR_TXT.resrec.rdata->MaxRDLength < txtlen)
6864*4b22b933Srs200217 sr->RR_TXT.resrec.rdata->MaxRDLength = txtlen;
6865*4b22b933Srs200217
6866*4b22b933Srs200217 // Set up the record names
6867*4b22b933Srs200217 // For now we only create an advisory record for the main type, not for subtypes
6868*4b22b933Srs200217 // We need to gain some operational experience before we decide if there's a need to create them for subtypes too
6869*4b22b933Srs200217 if (ConstructServiceName(sr->RR_ADV.resrec.name, (domainlabel*)"\x09_services", (domainname*)"\x07_dns-sd\x04_udp", domain) == mDNSNULL)
6870*4b22b933Srs200217 return(mStatus_BadParamErr);
6871*4b22b933Srs200217 if (ConstructServiceName(sr->RR_PTR.resrec.name, mDNSNULL, type, domain) == mDNSNULL) return(mStatus_BadParamErr);
6872*4b22b933Srs200217 if (ConstructServiceName(sr->RR_SRV.resrec.name, name, type, domain) == mDNSNULL) return(mStatus_BadParamErr);
6873*4b22b933Srs200217 AssignDomainName(sr->RR_TXT.resrec.name, sr->RR_SRV.resrec.name);
6874*4b22b933Srs200217
6875*4b22b933Srs200217 // 1. Set up the ADV record rdata to advertise our service type
6876*4b22b933Srs200217 AssignDomainName(&sr->RR_ADV.resrec.rdata->u.name, sr->RR_PTR.resrec.name);
6877*4b22b933Srs200217
6878*4b22b933Srs200217 // 2. Set up the PTR record rdata to point to our service name
6879*4b22b933Srs200217 // We set up two additionals, so when a client asks for this PTR we automatically send the SRV and the TXT too
6880*4b22b933Srs200217 AssignDomainName(&sr->RR_PTR.resrec.rdata->u.name, sr->RR_SRV.resrec.name);
6881*4b22b933Srs200217 sr->RR_PTR.Additional1 = &sr->RR_SRV;
6882*4b22b933Srs200217 sr->RR_PTR.Additional2 = &sr->RR_TXT;
6883*4b22b933Srs200217
6884*4b22b933Srs200217 // 2a. Set up any subtype PTRs to point to our service name
6885*4b22b933Srs200217 // If the client is using subtypes, it is the client's responsibility to have
6886*4b22b933Srs200217 // already set the first label of the record name to the subtype being registered
6887*4b22b933Srs200217 for (i=0; i<NumSubTypes; i++)
6888*4b22b933Srs200217 {
6889*4b22b933Srs200217 domainname st;
6890*4b22b933Srs200217 AssignDomainName(&st, sr->SubTypes[i].resrec.name);
6891*4b22b933Srs200217 st.c[1+st.c[0]] = 0; // Only want the first label, not the whole FQDN (particularly for mDNS_RenameAndReregisterService())
6892*4b22b933Srs200217 AppendDomainName(&st, type);
6893*4b22b933Srs200217 mDNS_SetupResourceRecord(&sr->SubTypes[i], mDNSNULL, InterfaceID, kDNSType_PTR, kStandardTTL, kDNSRecordTypeShared, ServiceCallback, sr);
6894*4b22b933Srs200217 if (ConstructServiceName(sr->SubTypes[i].resrec.name, mDNSNULL, &st, domain) == mDNSNULL) return(mStatus_BadParamErr);
6895*4b22b933Srs200217 AssignDomainName(&sr->SubTypes[i].resrec.rdata->u.name, sr->RR_SRV.resrec.name);
6896*4b22b933Srs200217 sr->SubTypes[i].Additional1 = &sr->RR_SRV;
6897*4b22b933Srs200217 sr->SubTypes[i].Additional2 = &sr->RR_TXT;
6898*4b22b933Srs200217 }
6899*4b22b933Srs200217
6900*4b22b933Srs200217 // 3. Set up the SRV record rdata.
6901*4b22b933Srs200217 sr->RR_SRV.resrec.rdata->u.srv.priority = 0;
6902*4b22b933Srs200217 sr->RR_SRV.resrec.rdata->u.srv.weight = 0;
6903*4b22b933Srs200217 sr->RR_SRV.resrec.rdata->u.srv.port = port;
6904*4b22b933Srs200217
6905*4b22b933Srs200217 // Setting HostTarget tells DNS that the target of this SRV is to be automatically kept in sync with our host name
6906*4b22b933Srs200217 if (sr->Host.c[0]) AssignDomainName(&sr->RR_SRV.resrec.rdata->u.srv.target, &sr->Host);
6907*4b22b933Srs200217 else { sr->RR_SRV.HostTarget = mDNStrue; sr->RR_SRV.resrec.rdata->u.srv.target.c[0] = '\0'; }
6908*4b22b933Srs200217
6909*4b22b933Srs200217 // 4. Set up the TXT record rdata,
6910*4b22b933Srs200217 // and set DependentOn because we're depending on the SRV record to find and resolve conflicts for us
6911*4b22b933Srs200217 if (txtinfo == mDNSNULL) sr->RR_TXT.resrec.rdlength = 0;
6912*4b22b933Srs200217 else if (txtinfo != sr->RR_TXT.resrec.rdata->u.txt.c)
6913*4b22b933Srs200217 {
6914*4b22b933Srs200217 sr->RR_TXT.resrec.rdlength = txtlen;
6915*4b22b933Srs200217 if (sr->RR_TXT.resrec.rdlength > sr->RR_TXT.resrec.rdata->MaxRDLength) return(mStatus_BadParamErr);
6916*4b22b933Srs200217 mDNSPlatformMemCopy(txtinfo, sr->RR_TXT.resrec.rdata->u.txt.c, txtlen);
6917*4b22b933Srs200217 }
6918*4b22b933Srs200217 sr->RR_TXT.DependentOn = &sr->RR_SRV;
6919*4b22b933Srs200217
6920*4b22b933Srs200217 #ifndef UNICAST_DISABLED
6921*4b22b933Srs200217 // If the client has specified an explicit InterfaceID,
6922*4b22b933Srs200217 // then we do a multicast registration on that interface, even for unicast domains.
6923*4b22b933Srs200217 if (!(InterfaceID == mDNSInterface_LocalOnly || IsLocalDomain(sr->RR_SRV.resrec.name)))
6924*4b22b933Srs200217 {
6925*4b22b933Srs200217 mStatus status;
6926*4b22b933Srs200217 mDNS_Lock(m);
6927*4b22b933Srs200217 // BIND named (name daemon) doesn't allow TXT records with zero-length rdata. This is strictly speaking correct,
6928*4b22b933Srs200217 // since RFC 1035 specifies a TXT record as "One or more <character-string>s", not "Zero or more <character-string>s".
6929*4b22b933Srs200217 // Since some legacy apps try to create zero-length TXT records, we'll silently correct it here.
6930*4b22b933Srs200217 // (We have to duplicate this check here because uDNS_RegisterService() bypasses the usual mDNS_Register_internal() bottleneck)
6931*4b22b933Srs200217 if (!sr->RR_TXT.resrec.rdlength) { sr->RR_TXT.resrec.rdlength = 1; sr->RR_TXT.resrec.rdata->u.txt.c[0] = 0; }
6932*4b22b933Srs200217 status = uDNS_RegisterService(m, sr);
6933*4b22b933Srs200217 mDNS_Unlock(m);
6934*4b22b933Srs200217 return(status);
6935*4b22b933Srs200217 }
6936*4b22b933Srs200217 #endif
6937*4b22b933Srs200217 mDNS_Lock(m);
6938*4b22b933Srs200217 err = mDNS_Register_internal(m, &sr->RR_SRV);
6939*4b22b933Srs200217 if (!err) err = mDNS_Register_internal(m, &sr->RR_TXT);
6940*4b22b933Srs200217 // We register the RR_PTR last, because we want to be sure that in the event of a forced call to
6941*4b22b933Srs200217 // mDNS_Close, the RR_PTR will be the last one to be forcibly deregistered, since that is what triggers
6942*4b22b933Srs200217 // the mStatus_MemFree callback to ServiceCallback, which in turn passes on the mStatus_MemFree back to
6943*4b22b933Srs200217 // the client callback, which is then at liberty to free the ServiceRecordSet memory at will. We need to
6944*4b22b933Srs200217 // make sure we've deregistered all our records and done any other necessary cleanup before that happens.
6945*4b22b933Srs200217 if (!err) err = mDNS_Register_internal(m, &sr->RR_ADV);
6946*4b22b933Srs200217 for (i=0; i<NumSubTypes; i++) if (!err) err = mDNS_Register_internal(m, &sr->SubTypes[i]);
6947*4b22b933Srs200217 if (!err) err = mDNS_Register_internal(m, &sr->RR_PTR);
6948*4b22b933Srs200217
6949*4b22b933Srs200217 mDNS_Unlock(m);
6950*4b22b933Srs200217
6951*4b22b933Srs200217 if (err) mDNS_DeregisterService(m, sr);
6952*4b22b933Srs200217 return(err);
6953*4b22b933Srs200217 }
6954*4b22b933Srs200217
mDNS_AddRecordToService(mDNS * const m,ServiceRecordSet * sr,ExtraResourceRecord * extra,RData * rdata,mDNSu32 ttl)6955*4b22b933Srs200217 mDNSexport mStatus mDNS_AddRecordToService(mDNS *const m, ServiceRecordSet *sr,
6956*4b22b933Srs200217 ExtraResourceRecord *extra, RData *rdata, mDNSu32 ttl)
6957*4b22b933Srs200217 {
6958*4b22b933Srs200217 ExtraResourceRecord **e;
6959*4b22b933Srs200217 mStatus status;
6960*4b22b933Srs200217
6961*4b22b933Srs200217 extra->next = mDNSNULL;
6962*4b22b933Srs200217 mDNS_SetupResourceRecord(&extra->r, rdata, sr->RR_PTR.resrec.InterfaceID,
6963*4b22b933Srs200217 extra->r.resrec.rrtype, ttl, kDNSRecordTypeUnique, ServiceCallback, sr);
6964*4b22b933Srs200217 AssignDomainName(extra->r.resrec.name, sr->RR_SRV.resrec.name);
6965*4b22b933Srs200217
6966*4b22b933Srs200217 #ifndef UNICAST_DISABLED
6967*4b22b933Srs200217 if (!(sr->RR_SRV.resrec.InterfaceID == mDNSInterface_LocalOnly || IsLocalDomain(sr->RR_SRV.resrec.name)))
6968*4b22b933Srs200217 {
6969*4b22b933Srs200217 mDNS_Lock(m);
6970*4b22b933Srs200217 // BIND named (name daemon) doesn't allow TXT records with zero-length rdata. This is strictly speaking correct,
6971*4b22b933Srs200217 // since RFC 1035 specifies a TXT record as "One or more <character-string>s", not "Zero or more <character-string>s".
6972*4b22b933Srs200217 // Since some legacy apps try to create zero-length TXT records, we'll silently correct it here.
6973*4b22b933Srs200217 // (We have to duplicate this check here because uDNS_AddRecordToService() bypasses the usual mDNS_Register_internal() bottleneck)
6974*4b22b933Srs200217 if (extra->r.resrec.rrtype == kDNSType_TXT && extra->r.resrec.rdlength == 0)
6975*4b22b933Srs200217 { extra->r.resrec.rdlength = 1; extra->r.resrec.rdata->u.txt.c[0] = 0; }
6976*4b22b933Srs200217 status = uDNS_AddRecordToService(m, sr, extra);
6977*4b22b933Srs200217 mDNS_Unlock(m);
6978*4b22b933Srs200217 return status;
6979*4b22b933Srs200217 }
6980*4b22b933Srs200217 #endif
6981*4b22b933Srs200217
6982*4b22b933Srs200217 mDNS_Lock(m);
6983*4b22b933Srs200217 e = &sr->Extras;
6984*4b22b933Srs200217 while (*e) e = &(*e)->next;
6985*4b22b933Srs200217
6986*4b22b933Srs200217 if (ttl == 0) ttl = kStandardTTL;
6987*4b22b933Srs200217
6988*4b22b933Srs200217 extra->r.DependentOn = &sr->RR_SRV;
6989*4b22b933Srs200217
6990*4b22b933Srs200217 debugf("mDNS_AddRecordToService adding record to %##s", extra->r.resrec.name->c);
6991*4b22b933Srs200217
6992*4b22b933Srs200217 status = mDNS_Register_internal(m, &extra->r);
6993*4b22b933Srs200217 if (status == mStatus_NoError) *e = extra;
6994*4b22b933Srs200217 mDNS_Unlock(m);
6995*4b22b933Srs200217 return(status);
6996*4b22b933Srs200217 }
6997*4b22b933Srs200217
mDNS_RemoveRecordFromService(mDNS * const m,ServiceRecordSet * sr,ExtraResourceRecord * extra,mDNSRecordCallback MemFreeCallback,void * Context)6998*4b22b933Srs200217 mDNSexport mStatus mDNS_RemoveRecordFromService(mDNS *const m, ServiceRecordSet *sr, ExtraResourceRecord *extra,
6999*4b22b933Srs200217 mDNSRecordCallback MemFreeCallback, void *Context)
7000*4b22b933Srs200217 {
7001*4b22b933Srs200217 ExtraResourceRecord **e;
7002*4b22b933Srs200217 mStatus status;
7003*4b22b933Srs200217
7004*4b22b933Srs200217 mDNS_Lock(m);
7005*4b22b933Srs200217 e = &sr->Extras;
7006*4b22b933Srs200217 while (*e && *e != extra) e = &(*e)->next;
7007*4b22b933Srs200217 if (!*e)
7008*4b22b933Srs200217 {
7009*4b22b933Srs200217 debugf("mDNS_RemoveRecordFromService failed to remove record from %##s", extra->r.resrec.name->c);
7010*4b22b933Srs200217 status = mStatus_BadReferenceErr;
7011*4b22b933Srs200217 }
7012*4b22b933Srs200217 else
7013*4b22b933Srs200217 {
7014*4b22b933Srs200217 debugf("mDNS_RemoveRecordFromService removing record from %##s", extra->r.resrec.name->c);
7015*4b22b933Srs200217 extra->r.RecordCallback = MemFreeCallback;
7016*4b22b933Srs200217 extra->r.RecordContext = Context;
7017*4b22b933Srs200217 *e = (*e)->next;
7018*4b22b933Srs200217 #ifndef UNICAST_DISABLED
7019*4b22b933Srs200217 if (!(sr->RR_SRV.resrec.InterfaceID == mDNSInterface_LocalOnly || IsLocalDomain(sr->RR_SRV.resrec.name)))
7020*4b22b933Srs200217 status = uDNS_DeregisterRecord(m, &extra->r);
7021*4b22b933Srs200217 else
7022*4b22b933Srs200217 #endif
7023*4b22b933Srs200217 status = mDNS_Deregister_internal(m, &extra->r, mDNS_Dereg_normal);
7024*4b22b933Srs200217 }
7025*4b22b933Srs200217 mDNS_Unlock(m);
7026*4b22b933Srs200217 return(status);
7027*4b22b933Srs200217 }
7028*4b22b933Srs200217
mDNS_RenameAndReregisterService(mDNS * const m,ServiceRecordSet * const sr,const domainlabel * newname)7029*4b22b933Srs200217 mDNSexport mStatus mDNS_RenameAndReregisterService(mDNS *const m, ServiceRecordSet *const sr, const domainlabel *newname)
7030*4b22b933Srs200217 {
7031*4b22b933Srs200217 // NOTE: Don't need to use mDNS_Lock(m) here, because this code is just using public routines
7032*4b22b933Srs200217 // mDNS_RegisterService() and mDNS_AddRecordToService(), which do the right locking internally.
7033*4b22b933Srs200217 domainlabel name1, name2;
7034*4b22b933Srs200217 domainname type, domain;
7035*4b22b933Srs200217 domainname *host = mDNSNULL;
7036*4b22b933Srs200217 ExtraResourceRecord *extras = sr->Extras;
7037*4b22b933Srs200217 mStatus err;
7038*4b22b933Srs200217
7039*4b22b933Srs200217 DeconstructServiceName(sr->RR_SRV.resrec.name, &name1, &type, &domain);
7040*4b22b933Srs200217 if (!newname)
7041*4b22b933Srs200217 {
7042*4b22b933Srs200217 name2 = name1;
7043*4b22b933Srs200217 IncrementLabelSuffix(&name2, mDNStrue);
7044*4b22b933Srs200217 newname = &name2;
7045*4b22b933Srs200217 }
7046*4b22b933Srs200217
7047*4b22b933Srs200217 if (SameDomainName(&domain, &localdomain))
7048*4b22b933Srs200217 LogMsg("%##s service renamed from \"%#s\" to \"%#s\"", type.c, name1.c, newname->c);
7049*4b22b933Srs200217 else LogMsg("%##s service (domain %##s) renamed from \"%#s\" to \"%#s\"",type.c, domain.c, name1.c, newname->c);
7050*4b22b933Srs200217
7051*4b22b933Srs200217 if (sr->RR_SRV.HostTarget == mDNSfalse && sr->Host.c[0]) host = &sr->Host;
7052*4b22b933Srs200217
7053*4b22b933Srs200217 err = mDNS_RegisterService(m, sr, newname, &type, &domain,
7054*4b22b933Srs200217 host, sr->RR_SRV.resrec.rdata->u.srv.port, sr->RR_TXT.resrec.rdata->u.txt.c, sr->RR_TXT.resrec.rdlength,
7055*4b22b933Srs200217 sr->SubTypes, sr->NumSubTypes,
7056*4b22b933Srs200217 sr->RR_PTR.resrec.InterfaceID, sr->ServiceCallback, sr->ServiceContext);
7057*4b22b933Srs200217
7058*4b22b933Srs200217 // mDNS_RegisterService() just reset sr->Extras to NULL.
7059*4b22b933Srs200217 // Fortunately we already grabbed ourselves a copy of this pointer (above), so we can now run
7060*4b22b933Srs200217 // through the old list of extra records, and re-add them to our freshly created service registration
7061*4b22b933Srs200217 while (!err && extras)
7062*4b22b933Srs200217 {
7063*4b22b933Srs200217 ExtraResourceRecord *e = extras;
7064*4b22b933Srs200217 extras = extras->next;
7065*4b22b933Srs200217 err = mDNS_AddRecordToService(m, sr, e, e->r.resrec.rdata, e->r.resrec.rroriginalttl);
7066*4b22b933Srs200217 }
7067*4b22b933Srs200217
7068*4b22b933Srs200217 return(err);
7069*4b22b933Srs200217 }
7070*4b22b933Srs200217
7071*4b22b933Srs200217 // NOTE: mDNS_DeregisterService calls mDNS_Deregister_internal which can call a user callback,
7072*4b22b933Srs200217 // which may change the record list and/or question list.
7073*4b22b933Srs200217 // Any code walking either list must use the CurrentQuestion and/or CurrentRecord mechanism to protect against this.
mDNS_DeregisterService(mDNS * const m,ServiceRecordSet * sr)7074*4b22b933Srs200217 mDNSexport mStatus mDNS_DeregisterService(mDNS *const m, ServiceRecordSet *sr)
7075*4b22b933Srs200217 {
7076*4b22b933Srs200217 // If port number is zero, that means this was actually registered using mDNS_RegisterNoSuchService()
7077*4b22b933Srs200217 if (!sr->RR_SRV.resrec.rdata->u.srv.port.NotAnInteger) return(mDNS_DeregisterNoSuchService(m, &sr->RR_SRV));
7078*4b22b933Srs200217
7079*4b22b933Srs200217 #ifndef UNICAST_DISABLED
7080*4b22b933Srs200217 if (!(sr->RR_SRV.resrec.InterfaceID == mDNSInterface_LocalOnly || IsLocalDomain(sr->RR_SRV.resrec.name)))
7081*4b22b933Srs200217 {
7082*4b22b933Srs200217 mStatus status;
7083*4b22b933Srs200217 mDNS_Lock(m);
7084*4b22b933Srs200217 status = uDNS_DeregisterService(m, sr);
7085*4b22b933Srs200217 mDNS_Unlock(m);
7086*4b22b933Srs200217 return(status);
7087*4b22b933Srs200217 }
7088*4b22b933Srs200217 #endif
7089*4b22b933Srs200217 if (sr->RR_PTR.resrec.RecordType == kDNSRecordTypeUnregistered)
7090*4b22b933Srs200217 {
7091*4b22b933Srs200217 debugf("Service set for %##s already deregistered", sr->RR_SRV.resrec.name->c);
7092*4b22b933Srs200217 return(mStatus_BadReferenceErr);
7093*4b22b933Srs200217 }
7094*4b22b933Srs200217 else if (sr->RR_PTR.resrec.RecordType == kDNSRecordTypeDeregistering)
7095*4b22b933Srs200217 {
7096*4b22b933Srs200217 debugf("Service set for %##s already in the process of deregistering", sr->RR_SRV.resrec.name->c);
7097*4b22b933Srs200217 return(mStatus_NoError);
7098*4b22b933Srs200217 }
7099*4b22b933Srs200217 else
7100*4b22b933Srs200217 {
7101*4b22b933Srs200217 mDNSu32 i;
7102*4b22b933Srs200217 mStatus status;
7103*4b22b933Srs200217 ExtraResourceRecord *e;
7104*4b22b933Srs200217 mDNS_Lock(m);
7105*4b22b933Srs200217 e = sr->Extras;
7106*4b22b933Srs200217
7107*4b22b933Srs200217 // We use mDNS_Dereg_repeat because, in the event of a collision, some or all of the
7108*4b22b933Srs200217 // SRV, TXT, or Extra records could have already been automatically deregistered, and that's okay
7109*4b22b933Srs200217 mDNS_Deregister_internal(m, &sr->RR_SRV, mDNS_Dereg_repeat);
7110*4b22b933Srs200217 mDNS_Deregister_internal(m, &sr->RR_TXT, mDNS_Dereg_repeat);
7111*4b22b933Srs200217
7112*4b22b933Srs200217 mDNS_Deregister_internal(m, &sr->RR_ADV, mDNS_Dereg_normal);
7113*4b22b933Srs200217
7114*4b22b933Srs200217 // We deregister all of the extra records, but we leave the sr->Extras list intact
7115*4b22b933Srs200217 // in case the client wants to do a RenameAndReregister and reinstate the registration
7116*4b22b933Srs200217 while (e)
7117*4b22b933Srs200217 {
7118*4b22b933Srs200217 mDNS_Deregister_internal(m, &e->r, mDNS_Dereg_repeat);
7119*4b22b933Srs200217 e = e->next;
7120*4b22b933Srs200217 }
7121*4b22b933Srs200217
7122*4b22b933Srs200217 for (i=0; i<sr->NumSubTypes; i++)
7123*4b22b933Srs200217 mDNS_Deregister_internal(m, &sr->SubTypes[i], mDNS_Dereg_normal);
7124*4b22b933Srs200217
7125*4b22b933Srs200217 // Be sure to deregister the PTR last!
7126*4b22b933Srs200217 // Deregistering this record is what triggers the mStatus_MemFree callback to ServiceCallback,
7127*4b22b933Srs200217 // which in turn passes on the mStatus_MemFree (or mStatus_NameConflict) back to the client callback,
7128*4b22b933Srs200217 // which is then at liberty to free the ServiceRecordSet memory at will. We need to make sure
7129*4b22b933Srs200217 // we've deregistered all our records and done any other necessary cleanup before that happens.
7130*4b22b933Srs200217 status = mDNS_Deregister_internal(m, &sr->RR_PTR, mDNS_Dereg_normal);
7131*4b22b933Srs200217 mDNS_Unlock(m);
7132*4b22b933Srs200217 return(status);
7133*4b22b933Srs200217 }
7134*4b22b933Srs200217 }
7135*4b22b933Srs200217
7136*4b22b933Srs200217 // Create a registration that asserts that no such service exists with this name.
7137*4b22b933Srs200217 // This can be useful where there is a given function is available through several protocols.
7138*4b22b933Srs200217 // For example, a printer called "Stuart's Printer" may implement printing via the "pdl-datastream" and "IPP"
7139*4b22b933Srs200217 // protocols, but not via "LPR". In this case it would be prudent for the printer to assert the non-existence of an
7140*4b22b933Srs200217 // "LPR" service called "Stuart's Printer". Without this precaution, another printer than offers only "LPR" printing
7141*4b22b933Srs200217 // could inadvertently advertise its service under the same name "Stuart's Printer", which might be confusing for users.
mDNS_RegisterNoSuchService(mDNS * const m,AuthRecord * const rr,const domainlabel * const name,const domainname * const type,const domainname * const domain,const domainname * const host,const mDNSInterfaceID InterfaceID,mDNSRecordCallback Callback,void * Context)7142*4b22b933Srs200217 mDNSexport mStatus mDNS_RegisterNoSuchService(mDNS *const m, AuthRecord *const rr,
7143*4b22b933Srs200217 const domainlabel *const name, const domainname *const type, const domainname *const domain,
7144*4b22b933Srs200217 const domainname *const host,
7145*4b22b933Srs200217 const mDNSInterfaceID InterfaceID, mDNSRecordCallback Callback, void *Context)
7146*4b22b933Srs200217 {
7147*4b22b933Srs200217 mDNS_SetupResourceRecord(rr, mDNSNULL, InterfaceID, kDNSType_SRV, kHostNameTTL, kDNSRecordTypeUnique, Callback, Context);
7148*4b22b933Srs200217 if (ConstructServiceName(rr->resrec.name, name, type, domain) == mDNSNULL) return(mStatus_BadParamErr);
7149*4b22b933Srs200217 rr->resrec.rdata->u.srv.priority = 0;
7150*4b22b933Srs200217 rr->resrec.rdata->u.srv.weight = 0;
7151*4b22b933Srs200217 rr->resrec.rdata->u.srv.port = zeroIPPort;
7152*4b22b933Srs200217 if (host && host->c[0]) AssignDomainName(&rr->resrec.rdata->u.srv.target, host);
7153*4b22b933Srs200217 else rr->HostTarget = mDNStrue;
7154*4b22b933Srs200217 return(mDNS_Register(m, rr));
7155*4b22b933Srs200217 }
7156*4b22b933Srs200217
mDNS_AdvertiseDomains(mDNS * const m,AuthRecord * rr,mDNS_DomainType DomainType,const mDNSInterfaceID InterfaceID,char * domname)7157*4b22b933Srs200217 mDNSexport mStatus mDNS_AdvertiseDomains(mDNS *const m, AuthRecord *rr,
7158*4b22b933Srs200217 mDNS_DomainType DomainType, const mDNSInterfaceID InterfaceID, char *domname)
7159*4b22b933Srs200217 {
7160*4b22b933Srs200217 mDNS_SetupResourceRecord(rr, mDNSNULL, InterfaceID, kDNSType_PTR, kStandardTTL, kDNSRecordTypeShared, mDNSNULL, mDNSNULL);
7161*4b22b933Srs200217 if (!MakeDomainNameFromDNSNameString(rr->resrec.name, mDNS_DomainTypeNames[DomainType])) return(mStatus_BadParamErr);
7162*4b22b933Srs200217 if (!MakeDomainNameFromDNSNameString(&rr->resrec.rdata->u.name, domname)) return(mStatus_BadParamErr);
7163*4b22b933Srs200217 return(mDNS_Register(m, rr));
7164*4b22b933Srs200217 }
7165*4b22b933Srs200217
7166*4b22b933Srs200217 // ***************************************************************************
7167*4b22b933Srs200217 #if COMPILER_LIKES_PRAGMA_MARK
7168*4b22b933Srs200217 #pragma mark -
7169*4b22b933Srs200217 #pragma mark -
7170*4b22b933Srs200217 #pragma mark - Startup and Shutdown
7171*4b22b933Srs200217 #endif
7172*4b22b933Srs200217
mDNS_GrowCache_internal(mDNS * const m,CacheEntity * storage,mDNSu32 numrecords)7173*4b22b933Srs200217 mDNSlocal void mDNS_GrowCache_internal(mDNS *const m, CacheEntity *storage, mDNSu32 numrecords)
7174*4b22b933Srs200217 {
7175*4b22b933Srs200217 if (storage && numrecords)
7176*4b22b933Srs200217 {
7177*4b22b933Srs200217 mDNSu32 i;
7178*4b22b933Srs200217 debugf("Adding cache storage for %d more records (%d bytes)", numrecords, numrecords*sizeof(CacheEntity));
7179*4b22b933Srs200217 for (i=0; i<numrecords; i++) storage[i].next = &storage[i+1];
7180*4b22b933Srs200217 storage[numrecords-1].next = m->rrcache_free;
7181*4b22b933Srs200217 m->rrcache_free = storage;
7182*4b22b933Srs200217 m->rrcache_size += numrecords;
7183*4b22b933Srs200217 }
7184*4b22b933Srs200217 }
7185*4b22b933Srs200217
mDNS_GrowCache(mDNS * const m,CacheEntity * storage,mDNSu32 numrecords)7186*4b22b933Srs200217 mDNSexport void mDNS_GrowCache(mDNS *const m, CacheEntity *storage, mDNSu32 numrecords)
7187*4b22b933Srs200217 {
7188*4b22b933Srs200217 mDNS_Lock(m);
7189*4b22b933Srs200217 mDNS_GrowCache_internal(m, storage, numrecords);
7190*4b22b933Srs200217 mDNS_Unlock(m);
7191*4b22b933Srs200217 }
7192*4b22b933Srs200217
mDNS_Init(mDNS * const m,mDNS_PlatformSupport * const p,CacheEntity * rrcachestorage,mDNSu32 rrcachesize,mDNSBool AdvertiseLocalAddresses,mDNSCallback * Callback,void * Context)7193*4b22b933Srs200217 mDNSexport mStatus mDNS_Init(mDNS *const m, mDNS_PlatformSupport *const p,
7194*4b22b933Srs200217 CacheEntity *rrcachestorage, mDNSu32 rrcachesize,
7195*4b22b933Srs200217 mDNSBool AdvertiseLocalAddresses, mDNSCallback *Callback, void *Context)
7196*4b22b933Srs200217 {
7197*4b22b933Srs200217 mDNSu32 slot;
7198*4b22b933Srs200217 mDNSs32 timenow;
7199*4b22b933Srs200217 mStatus result;
7200*4b22b933Srs200217
7201*4b22b933Srs200217 if (!rrcachestorage) rrcachesize = 0;
7202*4b22b933Srs200217
7203*4b22b933Srs200217 m->p = p;
7204*4b22b933Srs200217 m->KnownBugs = 0;
7205*4b22b933Srs200217 m->CanReceiveUnicastOn5353 = mDNSfalse; // Assume we can't receive unicasts on 5353, unless platform layer tells us otherwise
7206*4b22b933Srs200217 m->AdvertiseLocalAddresses = AdvertiseLocalAddresses;
7207*4b22b933Srs200217 m->mDNSPlatformStatus = mStatus_Waiting;
7208*4b22b933Srs200217 m->UnicastPort4 = zeroIPPort;
7209*4b22b933Srs200217 m->UnicastPort6 = zeroIPPort;
7210*4b22b933Srs200217 m->MainCallback = Callback;
7211*4b22b933Srs200217 m->MainContext = Context;
7212*4b22b933Srs200217 m->rec.r.resrec.RecordType = 0;
7213*4b22b933Srs200217
7214*4b22b933Srs200217 // For debugging: To catch and report locking failures
7215*4b22b933Srs200217 m->mDNS_busy = 0;
7216*4b22b933Srs200217 m->mDNS_reentrancy = 0;
7217*4b22b933Srs200217 m->mDNS_shutdown = mDNSfalse;
7218*4b22b933Srs200217 m->lock_rrcache = 0;
7219*4b22b933Srs200217 m->lock_Questions = 0;
7220*4b22b933Srs200217 m->lock_Records = 0;
7221*4b22b933Srs200217
7222*4b22b933Srs200217 // Task Scheduling variables
7223*4b22b933Srs200217 result = mDNSPlatformTimeInit();
7224*4b22b933Srs200217 if (result != mStatus_NoError) return(result);
7225*4b22b933Srs200217 m->timenow_adjust = (mDNSs32)mDNSRandom(0xFFFFFFFF);
7226*4b22b933Srs200217 timenow = mDNS_TimeNow_NoLock(m);
7227*4b22b933Srs200217
7228*4b22b933Srs200217 m->timenow = 0; // MUST only be set within mDNS_Lock/mDNS_Unlock section
7229*4b22b933Srs200217 m->timenow_last = timenow;
7230*4b22b933Srs200217 m->NextScheduledEvent = timenow;
7231*4b22b933Srs200217 m->SuppressSending = timenow;
7232*4b22b933Srs200217 m->NextCacheCheck = timenow + 0x78000000;
7233*4b22b933Srs200217 m->NextScheduledQuery = timenow + 0x78000000;
7234*4b22b933Srs200217 m->NextScheduledProbe = timenow + 0x78000000;
7235*4b22b933Srs200217 m->NextScheduledResponse = timenow + 0x78000000;
7236*4b22b933Srs200217 m->ExpectUnicastResponse = timenow + 0x78000000;
7237*4b22b933Srs200217 m->RandomQueryDelay = 0;
7238*4b22b933Srs200217 m->RandomReconfirmDelay = 0;
7239*4b22b933Srs200217 m->PktNum = 0;
7240*4b22b933Srs200217 m->SendDeregistrations = mDNSfalse;
7241*4b22b933Srs200217 m->SendImmediateAnswers = mDNSfalse;
7242*4b22b933Srs200217 m->SleepState = mDNSfalse;
7243*4b22b933Srs200217
7244*4b22b933Srs200217 // These fields only required for mDNS Searcher...
7245*4b22b933Srs200217 m->Questions = mDNSNULL;
7246*4b22b933Srs200217 m->NewQuestions = mDNSNULL;
7247*4b22b933Srs200217 m->CurrentQuestion = mDNSNULL;
7248*4b22b933Srs200217 m->LocalOnlyQuestions = mDNSNULL;
7249*4b22b933Srs200217 m->NewLocalOnlyQuestions = mDNSNULL;
7250*4b22b933Srs200217 m->rrcache_size = 0;
7251*4b22b933Srs200217 m->rrcache_totalused = 0;
7252*4b22b933Srs200217 m->rrcache_active = 0;
7253*4b22b933Srs200217 m->rrcache_report = 10;
7254*4b22b933Srs200217 m->rrcache_free = mDNSNULL;
7255*4b22b933Srs200217
7256*4b22b933Srs200217 for (slot = 0; slot < CACHE_HASH_SLOTS; slot++) m->rrcache_hash[slot] = mDNSNULL;
7257*4b22b933Srs200217
7258*4b22b933Srs200217 mDNS_GrowCache_internal(m, rrcachestorage, rrcachesize);
7259*4b22b933Srs200217
7260*4b22b933Srs200217 // Fields below only required for mDNS Responder...
7261*4b22b933Srs200217 m->hostlabel.c[0] = 0;
7262*4b22b933Srs200217 m->nicelabel.c[0] = 0;
7263*4b22b933Srs200217 m->MulticastHostname.c[0] = 0;
7264*4b22b933Srs200217 m->HIHardware.c[0] = 0;
7265*4b22b933Srs200217 m->HISoftware.c[0] = 0;
7266*4b22b933Srs200217 m->ResourceRecords = mDNSNULL;
7267*4b22b933Srs200217 m->DuplicateRecords = mDNSNULL;
7268*4b22b933Srs200217 m->NewLocalRecords = mDNSNULL;
7269*4b22b933Srs200217 m->CurrentRecord = mDNSNULL;
7270*4b22b933Srs200217 m->HostInterfaces = mDNSNULL;
7271*4b22b933Srs200217 m->ProbeFailTime = 0;
7272*4b22b933Srs200217 m->NumFailedProbes = 0;
7273*4b22b933Srs200217 m->SuppressProbes = 0;
7274*4b22b933Srs200217
7275*4b22b933Srs200217 #ifndef UNICAST_DISABLED
7276*4b22b933Srs200217 uDNS_Init(m);
7277*4b22b933Srs200217 m->SuppressStdPort53Queries = 0;
7278*4b22b933Srs200217 #endif
7279*4b22b933Srs200217 result = mDNSPlatformInit(m);
7280*4b22b933Srs200217
7281*4b22b933Srs200217 return(result);
7282*4b22b933Srs200217 }
7283*4b22b933Srs200217
mDNSCoreInitComplete(mDNS * const m,mStatus result)7284*4b22b933Srs200217 mDNSexport void mDNSCoreInitComplete(mDNS *const m, mStatus result)
7285*4b22b933Srs200217 {
7286*4b22b933Srs200217 m->mDNSPlatformStatus = result;
7287*4b22b933Srs200217 if (m->MainCallback)
7288*4b22b933Srs200217 {
7289*4b22b933Srs200217 mDNS_Lock(m);
7290*4b22b933Srs200217 m->mDNS_reentrancy++; // Increment to allow client to legally make mDNS API calls from the callback
7291*4b22b933Srs200217 m->MainCallback(m, mStatus_NoError);
7292*4b22b933Srs200217 m->mDNS_reentrancy--; // Decrement to block mDNS API calls again
7293*4b22b933Srs200217 mDNS_Unlock(m);
7294*4b22b933Srs200217 }
7295*4b22b933Srs200217 }
7296*4b22b933Srs200217
mDNS_Close(mDNS * const m)7297*4b22b933Srs200217 mDNSexport void mDNS_Close(mDNS *const m)
7298*4b22b933Srs200217 {
7299*4b22b933Srs200217 mDNSu32 rrcache_active = 0;
7300*4b22b933Srs200217 mDNSu32 rrcache_totalused = 0;
7301*4b22b933Srs200217 mDNSu32 slot;
7302*4b22b933Srs200217 NetworkInterfaceInfo *intf;
7303*4b22b933Srs200217 mDNS_Lock(m);
7304*4b22b933Srs200217
7305*4b22b933Srs200217 m->mDNS_shutdown = mDNStrue;
7306*4b22b933Srs200217
7307*4b22b933Srs200217 #ifndef UNICAST_DISABLED
7308*4b22b933Srs200217 uDNS_Close(m);
7309*4b22b933Srs200217 #endif
7310*4b22b933Srs200217 rrcache_totalused = m->rrcache_totalused;
7311*4b22b933Srs200217 for (slot = 0; slot < CACHE_HASH_SLOTS; slot++)
7312*4b22b933Srs200217 {
7313*4b22b933Srs200217 while(m->rrcache_hash[slot])
7314*4b22b933Srs200217 {
7315*4b22b933Srs200217 CacheGroup *cg = m->rrcache_hash[slot];
7316*4b22b933Srs200217 while (cg->members)
7317*4b22b933Srs200217 {
7318*4b22b933Srs200217 CacheRecord *rr = cg->members;
7319*4b22b933Srs200217 cg->members = cg->members->next;
7320*4b22b933Srs200217 if (rr->CRActiveQuestion) rrcache_active++;
7321*4b22b933Srs200217 ReleaseCacheRecord(m, rr);
7322*4b22b933Srs200217 }
7323*4b22b933Srs200217 cg->rrcache_tail = &cg->members;
7324*4b22b933Srs200217 ReleaseCacheGroup(m, &m->rrcache_hash[slot]);
7325*4b22b933Srs200217 }
7326*4b22b933Srs200217 }
7327*4b22b933Srs200217 debugf("mDNS_Close: RR Cache was using %ld records, %lu active", rrcache_totalused, rrcache_active);
7328*4b22b933Srs200217 if (rrcache_active != m->rrcache_active)
7329*4b22b933Srs200217 LogMsg("*** ERROR *** rrcache_active %lu != m->rrcache_active %lu", rrcache_active, m->rrcache_active);
7330*4b22b933Srs200217
7331*4b22b933Srs200217 for (intf = m->HostInterfaces; intf; intf = intf->next)
7332*4b22b933Srs200217 if (intf->Advertise)
7333*4b22b933Srs200217 DeadvertiseInterface(m, intf);
7334*4b22b933Srs200217
7335*4b22b933Srs200217 // Make sure there are nothing but deregistering records remaining in the list
7336*4b22b933Srs200217 if (m->CurrentRecord) LogMsg("mDNS_Close ERROR m->CurrentRecord already set");
7337*4b22b933Srs200217 m->CurrentRecord = m->ResourceRecords;
7338*4b22b933Srs200217 while (m->CurrentRecord)
7339*4b22b933Srs200217 {
7340*4b22b933Srs200217 AuthRecord *rr = m->CurrentRecord;
7341*4b22b933Srs200217 if (rr->resrec.RecordType != kDNSRecordTypeDeregistering)
7342*4b22b933Srs200217 {
7343*4b22b933Srs200217 debugf("mDNS_Close: Record type %X still in ResourceRecords list %##s", rr->resrec.RecordType, rr->resrec.name->c);
7344*4b22b933Srs200217 mDNS_Deregister_internal(m, rr, mDNS_Dereg_normal);
7345*4b22b933Srs200217 }
7346*4b22b933Srs200217 else
7347*4b22b933Srs200217 m->CurrentRecord = rr->next;
7348*4b22b933Srs200217 }
7349*4b22b933Srs200217
7350*4b22b933Srs200217 if (m->ResourceRecords) debugf("mDNS_Close: Sending final packets for deregistering records");
7351*4b22b933Srs200217 else debugf("mDNS_Close: No deregistering records remain");
7352*4b22b933Srs200217
7353*4b22b933Srs200217 // If any deregistering records remain, send their deregistration announcements before we exit
7354*4b22b933Srs200217 if (m->mDNSPlatformStatus != mStatus_NoError) DiscardDeregistrations(m);
7355*4b22b933Srs200217 else if (m->ResourceRecords) SendResponses(m);
7356*4b22b933Srs200217 if (m->ResourceRecords) LogMsg("mDNS_Close failed to send goodbye for: %s", ARDisplayString(m, m->ResourceRecords));
7357*4b22b933Srs200217
7358*4b22b933Srs200217 mDNS_Unlock(m);
7359*4b22b933Srs200217 debugf("mDNS_Close: mDNSPlatformClose");
7360*4b22b933Srs200217 mDNSPlatformClose(m);
7361*4b22b933Srs200217 debugf("mDNS_Close: done");
7362*4b22b933Srs200217 }
7363