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 Change History (most recent first):
18*4b22b933Srs200217
19*4b22b933Srs200217 $Log: uDNS.c,v $
20*4b22b933Srs200217 Revision 1.230.2.1 2006/08/29 06:24:23 cheshire
21*4b22b933Srs200217 Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
22*4b22b933Srs200217
23*4b22b933Srs200217 Revision 1.230 2006/06/29 03:02:44 cheshire
24*4b22b933Srs200217 <rdar://problem/4607042> mDNSResponder NXDOMAIN and CNAME support
25*4b22b933Srs200217
26*4b22b933Srs200217 Revision 1.229 2006/03/02 22:03:41 cheshire
27*4b22b933Srs200217 <rdar://problem/4395331> Spurious warning "GetLargeResourceRecord: m->rec appears to be already in use"
28*4b22b933Srs200217 Refinement: m->rec.r.resrec.RecordType needs to be cleared *every* time around for loop, not just once at the end
29*4b22b933Srs200217
30*4b22b933Srs200217 Revision 1.228 2006/02/26 00:54:42 cheshire
31*4b22b933Srs200217 Fixes to avoid code generation warning/error on FreeBSD 7
32*4b22b933Srs200217
33*4b22b933Srs200217 Revision 1.227 2006/01/09 20:47:05 cheshire
34*4b22b933Srs200217 <rdar://problem/4395331> Spurious warning "GetLargeResourceRecord: m->rec appears to be already in use"
35*4b22b933Srs200217
36*4b22b933Srs200217 Revision 1.226 2005/12/20 02:46:33 cheshire
37*4b22b933Srs200217 <rdar://problem/4175520> mDNSPosix wide-area registration broken
38*4b22b933Srs200217 Check too strict -- we can still do wide-area registration (without NAT-PMP)
39*4b22b933Srs200217 without having to know our gateway address
40*4b22b933Srs200217
41*4b22b933Srs200217 Revision 1.225 2005/10/21 22:51:17 cheshire
42*4b22b933Srs200217 <rdar://problem/4290265> Add check to avoid crashing NAT gateways that have buggy DNS relay code
43*4b22b933Srs200217 Refinement: Shorten "check-for-broken-dns-relay" to just "dnsbugtest"
44*4b22b933Srs200217 to avoid crashing NAT gateways that have a different DNS relay bug
45*4b22b933Srs200217
46*4b22b933Srs200217 Revision 1.224 2005/10/20 00:10:33 cheshire
47*4b22b933Srs200217 <rdar://problem/4290265> Add check to avoid crashing NAT gateways that have buggy DNS relay code
48*4b22b933Srs200217
49*4b22b933Srs200217 Revision 1.223 2005/10/17 18:52:42 cheshire
50*4b22b933Srs200217 <rdar://problem/4271183> mDNSResponder crashed in CheckRecordRegistrations
51*4b22b933Srs200217 Move code to unregister the service's extra records from uDNS_DeregisterService() to unlinkSRS().
52*4b22b933Srs200217
53*4b22b933Srs200217 Revision 1.222 2005/10/05 23:04:10 cheshire
54*4b22b933Srs200217 Add more information to unlinkAR and startLLQHandshakeCallback error messages
55*4b22b933Srs200217
56*4b22b933Srs200217 Revision 1.221 2005/10/05 17:27:48 herscher
57*4b22b933Srs200217 <rdar://problem/4272516> Change 200ms delay to 10ms
58*4b22b933Srs200217
59*4b22b933Srs200217 Revision 1.220 2005/09/24 01:10:09 cheshire
60*4b22b933Srs200217 Fix comment typos
61*4b22b933Srs200217
62*4b22b933Srs200217 Revision 1.219 2005/09/22 07:28:25 herscher
63*4b22b933Srs200217 Double the delay to 200000 usec after sending out a DNS query
64*4b22b933Srs200217
65*4b22b933Srs200217 Revision 1.218 2005/09/13 01:06:14 herscher
66*4b22b933Srs200217 <rdar://problem/4248878> Add 100ms delay in sendQuery.
67*4b22b933Srs200217
68*4b22b933Srs200217 Revision 1.217 2005/08/04 18:08:24 cheshire
69*4b22b933Srs200217 Update comments
70*4b22b933Srs200217
71*4b22b933Srs200217 Revision 1.216 2005/07/29 23:05:22 ksekar
72*4b22b933Srs200217 <rdar://problem/4137930> Hostname registration should register IPv6 AAAA record with DNS Update
73*4b22b933Srs200217 Services should point to IPv6 address if IPv4 NAT mapping fails
74*4b22b933Srs200217
75*4b22b933Srs200217 Revision 1.215 2005/07/29 21:01:51 ksekar
76*4b22b933Srs200217 <rdar://problem/4137930> Hostname registration should register IPv6 AAAA record with DNS Update
77*4b22b933Srs200217 correction to original checkin - misplaced return in HostnameCallback and logic error determining v6 changes
78*4b22b933Srs200217
79*4b22b933Srs200217 Revision 1.214 2005/07/29 19:46:10 ksekar
80*4b22b933Srs200217 <rdar://problem/4191860> reduce polling period on failed LLQs to 15 minutes
81*4b22b933Srs200217
82*4b22b933Srs200217 Revision 1.213 2005/07/29 18:04:22 ksekar
83*4b22b933Srs200217 <rdar://problem/4137930> Hostname registration should register IPv6 AAAA record with DNS Update
84*4b22b933Srs200217
85*4b22b933Srs200217 Revision 1.212 2005/07/22 19:35:50 ksekar
86*4b22b933Srs200217 <rdar://problem/4188821> SUTiger: LLQ event acknowledgments are not formated correctly
87*4b22b933Srs200217
88*4b22b933Srs200217 Revision 1.211 2005/07/21 18:51:04 ksekar
89*4b22b933Srs200217 <rdar://problem/4103136> mDNSResponder times out when mapping ports after sleep
90*4b22b933Srs200217
91*4b22b933Srs200217 Revision 1.210 2005/07/21 18:47:31 ksekar
92*4b22b933Srs200217 <rdar://problem/4137283> NAT-PMP refresh Requested Public Port should contain actual mapped port
93*4b22b933Srs200217
94*4b22b933Srs200217 Revision 1.209 2005/07/04 21:16:37 cheshire
95*4b22b933Srs200217 Minor code tidying -- initialize variables where they are declared
96*4b22b933Srs200217
97*4b22b933Srs200217 Revision 1.208 2005/06/28 00:24:28 ksekar
98*4b22b933Srs200217 <rdar://problem/4157823> memory smasher in conQueryCallback
99*4b22b933Srs200217
100*4b22b933Srs200217 Revision 1.207 2005/05/13 20:45:10 ksekar
101*4b22b933Srs200217 <rdar://problem/4074400> Rapid wide-area txt record updates don't work
102*4b22b933Srs200217
103*4b22b933Srs200217 Revision 1.206 2005/03/31 02:19:55 cheshire
104*4b22b933Srs200217 <rdar://problem/4021486> Fix build warnings
105*4b22b933Srs200217 Reviewed by: Scott Herscher
106*4b22b933Srs200217
107*4b22b933Srs200217 Revision 1.205 2005/03/21 00:33:51 shersche
108*4b22b933Srs200217 <rdar://problem/4021486> Fix build warnings on Win32 platform
109*4b22b933Srs200217
110*4b22b933Srs200217 Revision 1.204 2005/03/16 00:42:32 ksekar
111*4b22b933Srs200217 <rdar://problem/4012279> Long-lived queries not working on Windows
112*4b22b933Srs200217
113*4b22b933Srs200217 Revision 1.203 2005/03/04 03:00:03 ksekar
114*4b22b933Srs200217 <rdar://problem/4026546> Retransmissions happen too early, causing registrations to conflict with themselves
115*4b22b933Srs200217
116*4b22b933Srs200217 Revision 1.202 2005/03/01 19:29:17 ksekar
117*4b22b933Srs200217 changed LogMsgs to debugfs
118*4b22b933Srs200217
119*4b22b933Srs200217 Revision 1.201 2005/02/26 03:04:13 cheshire
120*4b22b933Srs200217 <rdar://problem/4017292> Should not indicate successful dynamic update if no network connection
121*4b22b933Srs200217 Don't try to do updates to root name server. This ensures status dot turns red if user
122*4b22b933Srs200217 enters a bad host name such as just "fred" instead of a properly fully-qualified name.
123*4b22b933Srs200217
124*4b22b933Srs200217 Revision 1.200 2005/02/25 17:47:45 ksekar
125*4b22b933Srs200217 <rdar://problem/4021868> SendServiceRegistration fails on wake from sleep
126*4b22b933Srs200217
127*4b22b933Srs200217 Revision 1.199 2005/02/25 04:21:00 cheshire
128*4b22b933Srs200217 <rdar://problem/4015377> mDNS -F returns the same domain multiple times with different casing
129*4b22b933Srs200217
130*4b22b933Srs200217 Revision 1.198 2005/02/25 02:35:22 cheshire
131*4b22b933Srs200217 <rdar://problem/4017292> Should not indicate successful dynamic update if no network connection
132*4b22b933Srs200217 If we get NXDomain error looking for the _dns-update._udp record,
133*4b22b933Srs200217 update status from 1 (in progress) to mStatus_NoSuchNameErr (failed)
134*4b22b933Srs200217
135*4b22b933Srs200217 Revision 1.197 2005/02/24 21:56:59 ksekar
136*4b22b933Srs200217 Change LogMsgs to debugfs
137*4b22b933Srs200217
138*4b22b933Srs200217 Revision 1.196 2005/02/24 21:52:28 ksekar
139*4b22b933Srs200217 <rdar://problem/3922768> Remove "deferred deregistration" logic for hostnames
140*4b22b933Srs200217
141*4b22b933Srs200217 Revision 1.195 2005/02/22 17:53:08 ksekar
142*4b22b933Srs200217 Changed successful NAT Traversals from LogMsg to LogOperation
143*4b22b933Srs200217
144*4b22b933Srs200217 Revision 1.194 2005/02/15 18:38:03 ksekar
145*4b22b933Srs200217 <rdar://problem/3967876> change expected/redundant log messages to debugfs.
146*4b22b933Srs200217
147*4b22b933Srs200217 Revision 1.193 2005/02/15 01:17:48 ksekar
148*4b22b933Srs200217 Fixed build failure.
149*4b22b933Srs200217
150*4b22b933Srs200217 Revision 1.192 2005/02/14 23:01:28 ksekar
151*4b22b933Srs200217 Refinement to previous checkin - don't log bad LLQ opcode if we had to send the request more than once.
152*4b22b933Srs200217
153*4b22b933Srs200217 Revision 1.191 2005/02/14 18:26:51 ksekar
154*4b22b933Srs200217 <rdar://problem/4005569> mDNSResponder complains about bad LLQ Opcode 2
155*4b22b933Srs200217
156*4b22b933Srs200217 Revision 1.190 2005/02/11 19:44:06 shersche
157*4b22b933Srs200217 Remove extra semicolon at end of line
158*4b22b933Srs200217
159*4b22b933Srs200217 Revision 1.189 2005/02/10 21:07:02 ksekar
160*4b22b933Srs200217 Don't goto error in ReceiveNATAddrResponse if we receive a malformatted response
161*4b22b933Srs200217
162*4b22b933Srs200217 Revision 1.188 2005/02/10 02:02:44 ksekar
163*4b22b933Srs200217 Remove double semi-colon
164*4b22b933Srs200217
165*4b22b933Srs200217 Revision 1.187 2005/02/09 23:28:01 ksekar
166*4b22b933Srs200217 <rdar://problem/3984374> NAT-PMP response callback should return a
167*4b22b933Srs200217 boolean indicating if the packet matched the request
168*4b22b933Srs200217
169*4b22b933Srs200217 Revision 1.186 2005/02/04 21:56:29 ksekar
170*4b22b933Srs200217 <rdar://problem/3984374> Simultaneous port map requests sometimes fail
171*4b22b933Srs200217 - Refinement to previous checkin.
172*4b22b933Srs200217
173*4b22b933Srs200217 Revision 1.185 2005/02/03 23:48:22 ksekar
174*4b22b933Srs200217 <rdar://problem/3984374> Simultaneous port map requests sometimes fail
175*4b22b933Srs200217
176*4b22b933Srs200217 Revision 1.184 2005/02/01 19:33:29 ksekar
177*4b22b933Srs200217 <rdar://problem/3985239> Keychain format too restrictive
178*4b22b933Srs200217
179*4b22b933Srs200217 Revision 1.183 2005/01/27 22:57:55 cheshire
180*4b22b933Srs200217 Fix compile errors on gcc4
181*4b22b933Srs200217
182*4b22b933Srs200217 Revision 1.182 2005/01/25 18:55:05 ksekar
183*4b22b933Srs200217 Shortened log message
184*4b22b933Srs200217
185*4b22b933Srs200217 Revision 1.181 2005/01/25 02:17:32 cheshire
186*4b22b933Srs200217 <rdar://problem/3971263> Don't use query ID zero in uDNS queries
187*4b22b933Srs200217
188*4b22b933Srs200217 Revision 1.180 2005/01/19 21:01:54 ksekar
189*4b22b933Srs200217 <rdar://problem/3955355> uDNS needs to support subtype registration and browsing
190*4b22b933Srs200217
191*4b22b933Srs200217 Revision 1.179 2005/01/19 19:15:35 ksekar
192*4b22b933Srs200217 Refinement to <rdar://problem/3954575> - Simplify mDNS_PurgeResultsForDomain logic and move into daemon layer
193*4b22b933Srs200217
194*4b22b933Srs200217 Revision 1.178 2005/01/17 23:47:58 cheshire
195*4b22b933Srs200217 <rdar://problem/3904954> Wide-area services not found on little-endian
196*4b22b933Srs200217
197*4b22b933Srs200217 Revision 1.177 2005/01/17 23:41:26 cheshire
198*4b22b933Srs200217 Fix compile errors
199*4b22b933Srs200217
200*4b22b933Srs200217 Revision 1.176 2005/01/17 21:03:04 cheshire
201*4b22b933Srs200217 <rdar://problem/3904954> Wide-area services not found on little-endian
202*4b22b933Srs200217
203*4b22b933Srs200217 Revision 1.175 2005/01/15 00:56:41 ksekar
204*4b22b933Srs200217 <rdar://problem/3954575> Unicast services don't disappear when logging
205*4b22b933Srs200217 out of VPN
206*4b22b933Srs200217
207*4b22b933Srs200217 Revision 1.174 2005/01/14 18:44:28 ksekar
208*4b22b933Srs200217 <rdar://problem/3954609> mDNSResponder is crashing when changing domains
209*4b22b933Srs200217
210*4b22b933Srs200217 Revision 1.173 2005/01/14 18:34:22 ksekar
211*4b22b933Srs200217 <rdar://problem/3954571> Services registered outside of firewall don't succeed after location change
212*4b22b933Srs200217
213*4b22b933Srs200217 Revision 1.172 2005/01/11 22:50:52 ksekar
214*4b22b933Srs200217 Fixed constant naming (was using kLLQ_DefLease for update leases)
215*4b22b933Srs200217
216*4b22b933Srs200217 Revision 1.171 2005/01/10 04:52:49 ksekar
217*4b22b933Srs200217 Changed LogMsg to debugf
218*4b22b933Srs200217
219*4b22b933Srs200217 Revision 1.170 2005/01/08 00:50:05 ksekar
220*4b22b933Srs200217 Fixed spelling mistake in log msg
221*4b22b933Srs200217
222*4b22b933Srs200217 Revision 1.169 2005/01/08 00:42:18 ksekar
223*4b22b933Srs200217 <rdar://problem/3922758> Clean up syslog messages
224*4b22b933Srs200217
225*4b22b933Srs200217 Revision 1.168 2004/12/23 23:22:47 ksekar
226*4b22b933Srs200217 <rdar://problem/3933606> Unicast known answers "name" pointers point to garbage stack memory
227*4b22b933Srs200217
228*4b22b933Srs200217 Revision 1.167 2004/12/22 22:25:47 ksekar
229*4b22b933Srs200217 <rdar://problem/3734265> NATPMP: handle location changes
230*4b22b933Srs200217
231*4b22b933Srs200217 Revision 1.166 2004/12/22 00:04:12 ksekar
232*4b22b933Srs200217 <rdar://problem/3930324> mDNSResponder crashing in ReceivePortMapReply
233*4b22b933Srs200217
234*4b22b933Srs200217 Revision 1.165 2004/12/18 03:14:22 cheshire
235*4b22b933Srs200217 DblNAT -> DoubleNAT
236*4b22b933Srs200217
237*4b22b933Srs200217 Revision 1.164 2004/12/17 03:55:40 ksekar
238*4b22b933Srs200217 Don't use -1 as special meaning for expiration timer (it is a valid
239*4b22b933Srs200217 value, and is redundant with our state variables)
240*4b22b933Srs200217
241*4b22b933Srs200217 Revision 1.163 2004/12/17 03:51:53 ksekar
242*4b22b933Srs200217 <rdar://problem/3920991> Don't update TXT record if service registration fails
243*4b22b933Srs200217
244*4b22b933Srs200217 Revision 1.162 2004/12/17 01:29:11 ksekar
245*4b22b933Srs200217 <rdar://problem/3920598> Questions can go deaf on location changes
246*4b22b933Srs200217
247*4b22b933Srs200217 Revision 1.161 2004/12/16 20:42:02 cheshire
248*4b22b933Srs200217 Fix compiler warnings
249*4b22b933Srs200217
250*4b22b933Srs200217 Revision 1.160 2004/12/16 20:13:00 cheshire
251*4b22b933Srs200217 <rdar://problem/3324626> Cache memory management improvements
252*4b22b933Srs200217
253*4b22b933Srs200217 Revision 1.159 2004/12/15 02:11:22 ksekar
254*4b22b933Srs200217 <rdar://problem/3917317> Don't check for Dynamic DNS hostname uniqueness
255*4b22b933Srs200217
256*4b22b933Srs200217 Revision 1.158 2004/12/15 02:04:28 ksekar
257*4b22b933Srs200217 Refinement to previous checkin - we should still return NatTraversal error when the port mapping fails
258*4b22b933Srs200217
259*4b22b933Srs200217 Revision 1.157 2004/12/15 01:39:21 ksekar
260*4b22b933Srs200217 Refinement to previous checkin - we should still return NatTraversal error when the port mapping fails
261*4b22b933Srs200217
262*4b22b933Srs200217 Revision 1.156 2004/12/15 01:18:57 ksekar
263*4b22b933Srs200217 <rdar://problem/3825979> Call DeregisterService on nat port map failure
264*4b22b933Srs200217
265*4b22b933Srs200217 Revision 1.155 2004/12/14 21:21:20 ksekar
266*4b22b933Srs200217 <rdar://problem/3825979> NAT-PMP: Update response format to contain "Seconds Since Boot"
267*4b22b933Srs200217
268*4b22b933Srs200217 Revision 1.154 2004/12/14 20:52:27 cheshire
269*4b22b933Srs200217 Add question->qnamehash and cr->resrec.namehash to log message
270*4b22b933Srs200217
271*4b22b933Srs200217 Revision 1.153 2004/12/14 20:45:02 cheshire
272*4b22b933Srs200217 Improved error logging in "unexpected answer" message
273*4b22b933Srs200217
274*4b22b933Srs200217 Revision 1.152 2004/12/14 03:02:10 ksekar
275*4b22b933Srs200217 <rdar://problem/3919016> Rare race condition can cause crash
276*4b22b933Srs200217
277*4b22b933Srs200217 Revision 1.151 2004/12/13 21:45:08 ksekar
278*4b22b933Srs200217 uDNS_DeregisterService should return NoError if called twice (to follow mDNS behavior expected by daemon layer)
279*4b22b933Srs200217
280*4b22b933Srs200217 Revision 1.150 2004/12/13 20:42:41 ksekar
281*4b22b933Srs200217 Fixed LogMsg
282*4b22b933Srs200217
283*4b22b933Srs200217 Revision 1.149 2004/12/13 18:10:03 ksekar
284*4b22b933Srs200217 Fixed LogMsg
285*4b22b933Srs200217
286*4b22b933Srs200217 Revision 1.148 2004/12/13 01:18:04 ksekar
287*4b22b933Srs200217 Fixed unused variable warning for non-debug builds
288*4b22b933Srs200217
289*4b22b933Srs200217 Revision 1.147 2004/12/12 23:51:42 ksekar
290*4b22b933Srs200217 <rdar://problem/3845683> Wide-area registrations should fallback to using DHCP hostname as target
291*4b22b933Srs200217
292*4b22b933Srs200217 Revision 1.146 2004/12/12 23:30:40 ksekar
293*4b22b933Srs200217 <rdar://problem/3916987> Extra RRs not properly unlinked when parent service registration fails
294*4b22b933Srs200217
295*4b22b933Srs200217 Revision 1.145 2004/12/12 22:56:29 ksekar
296*4b22b933Srs200217 <rdar://problem/3668508> Need to properly handle duplicate long-lived queries
297*4b22b933Srs200217
298*4b22b933Srs200217 Revision 1.144 2004/12/11 20:55:29 ksekar
299*4b22b933Srs200217 <rdar://problem/3916479> Clean up registration state machines
300*4b22b933Srs200217
301*4b22b933Srs200217 Revision 1.143 2004/12/10 01:21:27 cheshire
302*4b22b933Srs200217 <rdar://problem/3914089> Get rid of "LLQ Responses over TCP not currently supported" message
303*4b22b933Srs200217
304*4b22b933Srs200217 Revision 1.142 2004/12/08 02:03:31 ksekar
305*4b22b933Srs200217 <rdar://problem/3865124> Looping on NAT Traversal error - check for
306*4b22b933Srs200217 NULL RR on error
307*4b22b933Srs200217
308*4b22b933Srs200217 Revision 1.141 2004/12/07 01:39:28 cheshire
309*4b22b933Srs200217 Don't fail if the same server is responsible for more than one domain
310*4b22b933Srs200217 (e.g. the same DNS server may be responsible for both apple.com. and 17.in-addr.arpa.)
311*4b22b933Srs200217
312*4b22b933Srs200217 Revision 1.140 2004/12/06 21:15:22 ksekar
313*4b22b933Srs200217 <rdar://problem/3884386> mDNSResponder crashed in CheckServiceRegistrations
314*4b22b933Srs200217
315*4b22b933Srs200217 Revision 1.139 2004/12/06 19:08:03 cheshire
316*4b22b933Srs200217 Add clarifying comment -- CountLabels() excludes the final root label.
317*4b22b933Srs200217
318*4b22b933Srs200217 Revision 1.138 2004/12/06 01:45:54 ksekar
319*4b22b933Srs200217 Correct wording in LogMsg
320*4b22b933Srs200217
321*4b22b933Srs200217 Revision 1.137 2004/12/03 20:40:35 ksekar
322*4b22b933Srs200217 <rdar://problem/3865124> Looping on NAT Traversal error
323*4b22b933Srs200217
324*4b22b933Srs200217 Revision 1.136 2004/12/03 07:20:50 ksekar
325*4b22b933Srs200217 <rdar://problem/3674208> Wide-Area: Registration of large TXT record fails
326*4b22b933Srs200217
327*4b22b933Srs200217 Revision 1.135 2004/12/03 05:18:33 ksekar
328*4b22b933Srs200217 <rdar://problem/3810596> mDNSResponder needs to return more specific TSIG errors
329*4b22b933Srs200217
330*4b22b933Srs200217 Revision 1.134 2004/12/02 20:03:49 ksekar
331*4b22b933Srs200217 <rdar://problem/3889647> Still publishes wide-area domains even after switching to a local subnet
332*4b22b933Srs200217
333*4b22b933Srs200217 Revision 1.133 2004/12/02 18:37:52 ksekar
334*4b22b933Srs200217 <rdar://problem/3758233> Registering with port number zero should not create a port mapping
335*4b22b933Srs200217
336*4b22b933Srs200217 Revision 1.132 2004/12/01 20:57:19 ksekar
337*4b22b933Srs200217 <rdar://problem/3873921> Wide Area Service Discovery must be split-DNS aware
338*4b22b933Srs200217
339*4b22b933Srs200217 Revision 1.131 2004/12/01 19:59:27 cheshire
340*4b22b933Srs200217 <rdar://problem/3882643> Crash in mDNSPlatformTCPConnect
341*4b22b933Srs200217 If a TCP response has the TC bit set, don't respond by just trying another TCP connection
342*4b22b933Srs200217
343*4b22b933Srs200217 Revision 1.130 2004/12/01 02:43:23 cheshire
344*4b22b933Srs200217 Don't call StatusCallback if function pointer is null
345*4b22b933Srs200217
346*4b22b933Srs200217 Revision 1.129 2004/11/30 23:51:06 cheshire
347*4b22b933Srs200217 Remove double semicolons
348*4b22b933Srs200217
349*4b22b933Srs200217 Revision 1.128 2004/11/25 01:48:30 ksekar
350*4b22b933Srs200217 <rdar://problem/3878991> Logging into VPN does not trigger registration of address record
351*4b22b933Srs200217
352*4b22b933Srs200217 Revision 1.127 2004/11/25 01:41:36 ksekar
353*4b22b933Srs200217 Changed unnecessary LogMsgs to debugfs
354*4b22b933Srs200217
355*4b22b933Srs200217 Revision 1.126 2004/11/23 23:54:17 ksekar
356*4b22b933Srs200217 <rdar://problem/3890318> Wide-Area DNSServiceRegisterRecord() failures
357*4b22b933Srs200217 can crash mDNSResponder
358*4b22b933Srs200217
359*4b22b933Srs200217 Revision 1.125 2004/11/23 04:16:48 cheshire
360*4b22b933Srs200217 Removed receiveMsg() routine.
361*4b22b933Srs200217
362*4b22b933Srs200217 Revision 1.124 2004/11/23 04:06:51 cheshire
363*4b22b933Srs200217 Get rid of floating point constant -- in a small embedded device, bringing in all
364*4b22b933Srs200217 the floating point libraries just to halve an integer value is a bit too heavyweight.
365*4b22b933Srs200217
366*4b22b933Srs200217 Revision 1.123 2004/11/22 17:16:20 ksekar
367*4b22b933Srs200217 <rdar://problem/3854298> Unicast services don't disappear when you disable all networking
368*4b22b933Srs200217
369*4b22b933Srs200217 Revision 1.122 2004/11/19 18:00:34 ksekar
370*4b22b933Srs200217 <rdar://problem/3682646> Security: use random ID for one-shot unicast queries
371*4b22b933Srs200217
372*4b22b933Srs200217 Revision 1.121 2004/11/19 04:24:08 ksekar
373*4b22b933Srs200217 <rdar://problem/3682609> Security: Enforce a "window" on one-shot wide-area queries
374*4b22b933Srs200217
375*4b22b933Srs200217 Revision 1.120 2004/11/19 02:32:43 ksekar
376*4b22b933Srs200217 <rdar://problem/3682608> Wide-Area Security: Add LLQ-ID to events
377*4b22b933Srs200217
378*4b22b933Srs200217 Revision 1.119 2004/11/18 23:21:24 ksekar
379*4b22b933Srs200217 <rdar://problem/3764544> LLQ Security: Need to verify src port/address for LLQ handshake
380*4b22b933Srs200217
381*4b22b933Srs200217 Revision 1.118 2004/11/18 22:58:37 ksekar
382*4b22b933Srs200217 Removed old comment.
383*4b22b933Srs200217
384*4b22b933Srs200217 Revision 1.117 2004/11/18 18:04:21 ksekar
385*4b22b933Srs200217 Restore checkins lost due to repository disk failure: Update comments & <rdar://problem/3880688>
386*4b22b933Srs200217
387*4b22b933Srs200217 Revision 1.xxx 2004/11/17 06:17:57 cheshire
388*4b22b933Srs200217 Update comments to show correct SRV names: _dns-update._udp.<zone>. and _dns-llq._udp.<zone>.
389*4b22b933Srs200217
390*4b22b933Srs200217 Revision 1.xxx 2004/11/17 00:45:28 ksekar
391*4b22b933Srs200217 <rdar://problem/3880688> Result of putUpdateLease not error-checked
392*4b22b933Srs200217
393*4b22b933Srs200217 Revision 1.116 2004/11/16 01:41:47 ksekar
394*4b22b933Srs200217 Fixed typo in debugf
395*4b22b933Srs200217
396*4b22b933Srs200217 Revision 1.115 2004/11/15 20:09:24 ksekar
397*4b22b933Srs200217 <rdar://problem/3719050> Wide Area support for Add/Remove record
398*4b22b933Srs200217
399*4b22b933Srs200217 Revision 1.114 2004/11/13 02:32:47 ksekar
400*4b22b933Srs200217 <rdar://problem/3868216> LLQ mobility fragile on non-primary interface
401*4b22b933Srs200217 - fixed incorrect state comparison in CheckQueries
402*4b22b933Srs200217
403*4b22b933Srs200217 Revision 1.113 2004/11/13 02:29:52 ksekar
404*4b22b933Srs200217 <rdar://problem/3878386> LLQ refreshes not reliable
405*4b22b933Srs200217
406*4b22b933Srs200217 Revision 1.112 2004/11/11 20:45:14 ksekar
407*4b22b933Srs200217 <rdar://problem/3876052> self-conflict test not compatible with some BIND servers
408*4b22b933Srs200217
409*4b22b933Srs200217 Revision 1.111 2004/11/11 20:14:55 ksekar
410*4b22b933Srs200217 <rdar://problem/3719574> Wide-Area registrations not deregistered on sleep
411*4b22b933Srs200217
412*4b22b933Srs200217 Revision 1.110 2004/11/10 23:53:53 ksekar
413*4b22b933Srs200217 Remove no longer relevant comment
414*4b22b933Srs200217
415*4b22b933Srs200217 Revision 1.109 2004/11/10 20:40:53 ksekar
416*4b22b933Srs200217 <rdar://problem/3868216> LLQ mobility fragile on non-primary interface
417*4b22b933Srs200217
418*4b22b933Srs200217 Revision 1.108 2004/11/01 20:36:16 ksekar
419*4b22b933Srs200217 <rdar://problem/3802395> mDNSResponder should not receive Keychain Notifications
420*4b22b933Srs200217
421*4b22b933Srs200217 Revision 1.107 2004/10/26 06:11:41 cheshire
422*4b22b933Srs200217 Add improved logging to aid in diagnosis of <rdar://problem/3842714> mDNSResponder crashed
423*4b22b933Srs200217
424*4b22b933Srs200217 Revision 1.106 2004/10/26 03:52:03 cheshire
425*4b22b933Srs200217 Update checkin comments
426*4b22b933Srs200217
427*4b22b933Srs200217 Revision 1.105 2004/10/26 01:15:06 cheshire
428*4b22b933Srs200217 Use "#if 0" instead of commenting out code
429*4b22b933Srs200217
430*4b22b933Srs200217 Revision 1.104 2004/10/25 21:41:38 ksekar
431*4b22b933Srs200217 <rdar://problem/3852958> wide-area name conflicts can cause crash
432*4b22b933Srs200217
433*4b22b933Srs200217 Revision 1.103 2004/10/25 19:30:52 ksekar
434*4b22b933Srs200217 <rdar://problem/3827956> Simplify dynamic host name structures
435*4b22b933Srs200217
436*4b22b933Srs200217 Revision 1.102 2004/10/23 01:16:00 cheshire
437*4b22b933Srs200217 <rdar://problem/3851677> uDNS operations not always reliable on multi-homed hosts
438*4b22b933Srs200217
439*4b22b933Srs200217 Revision 1.101 2004/10/22 20:52:07 ksekar
440*4b22b933Srs200217 <rdar://problem/3799260> Create NAT port mappings for Long Lived Queries
441*4b22b933Srs200217
442*4b22b933Srs200217 Revision 1.100 2004/10/20 02:16:41 cheshire
443*4b22b933Srs200217 Improve "could not confirm existence of NS record" error message
444*4b22b933Srs200217 Don't call newRR->RecordCallback if it is NULL
445*4b22b933Srs200217
446*4b22b933Srs200217 Revision 1.99 2004/10/19 21:33:18 cheshire
447*4b22b933Srs200217 <rdar://problem/3844991> Cannot resolve non-local registrations using the mach API
448*4b22b933Srs200217 Added flag 'kDNSServiceFlagsForceMulticast'. Passing through an interface id for a unicast name
449*4b22b933Srs200217 doesn't force multicast unless you set this flag to indicate explicitly that this is what you want
450*4b22b933Srs200217
451*4b22b933Srs200217 Revision 1.98 2004/10/16 00:16:59 cheshire
452*4b22b933Srs200217 <rdar://problem/3770558> Replace IP TTL 255 check with local subnet source address check
453*4b22b933Srs200217
454*4b22b933Srs200217 Revision 1.97 2004/10/15 23:00:18 ksekar
455*4b22b933Srs200217 <rdar://problem/3799242> Need to update LLQs on location changes
456*4b22b933Srs200217
457*4b22b933Srs200217 Revision 1.96 2004/10/12 23:30:44 ksekar
458*4b22b933Srs200217 <rdar://problem/3609944> mDNSResponder needs to follow CNAME referrals
459*4b22b933Srs200217
460*4b22b933Srs200217 Revision 1.95 2004/10/12 03:15:09 ksekar
461*4b22b933Srs200217 <rdar://problem/3835612> mDNS_StartQuery shouldn't return transient no-server error
462*4b22b933Srs200217
463*4b22b933Srs200217 Revision 1.94 2004/10/12 02:49:20 ksekar
464*4b22b933Srs200217 <rdar://problem/3831228> Clean up LLQ sleep/wake, error handling
465*4b22b933Srs200217
466*4b22b933Srs200217 Revision 1.93 2004/10/08 04:17:25 ksekar
467*4b22b933Srs200217 <rdar://problem/3831819> Don't use DNS extensions if the server does not advertise required SRV record
468*4b22b933Srs200217
469*4b22b933Srs200217 Revision 1.92 2004/10/08 03:54:35 ksekar
470*4b22b933Srs200217 <rdar://problem/3831802> Refine unicast polling intervals
471*4b22b933Srs200217
472*4b22b933Srs200217 Revision 1.91 2004/09/30 17:45:34 ksekar
473*4b22b933Srs200217 <rdar://problem/3821119> lots of log messages: mDNS_SetPrimaryIP: IP address unchanged
474*4b22b933Srs200217
475*4b22b933Srs200217 Revision 1.90 2004/09/25 00:22:13 ksekar
476*4b22b933Srs200217 <rdar://problem/3815534> Crash in uDNS_RegisterService
477*4b22b933Srs200217
478*4b22b933Srs200217 Revision 1.89 2004/09/24 19:14:53 cheshire
479*4b22b933Srs200217 Remove unused "extern mDNS mDNSStorage"
480*4b22b933Srs200217
481*4b22b933Srs200217 Revision 1.88 2004/09/23 20:48:15 ksekar
482*4b22b933Srs200217 Clarify retransmission debugf messages.
483*4b22b933Srs200217
484*4b22b933Srs200217 Revision 1.87 2004/09/22 00:41:59 cheshire
485*4b22b933Srs200217 Move tcp connection status codes into the legal range allocated for mDNS use
486*4b22b933Srs200217
487*4b22b933Srs200217 Revision 1.86 2004/09/21 23:40:11 ksekar
488*4b22b933Srs200217 <rdar://problem/3810349> mDNSResponder to return errors on NAT traversal failure
489*4b22b933Srs200217
490*4b22b933Srs200217 Revision 1.85 2004/09/21 22:38:27 ksekar
491*4b22b933Srs200217 <rdar://problem/3810286> PrimaryIP type uninitialized
492*4b22b933Srs200217
493*4b22b933Srs200217 Revision 1.84 2004/09/18 00:30:39 cheshire
494*4b22b933Srs200217 <rdar://problem/3806643> Infinite loop in CheckServiceRegistrations
495*4b22b933Srs200217
496*4b22b933Srs200217 Revision 1.83 2004/09/17 00:31:51 cheshire
497*4b22b933Srs200217 For consistency with ipv6, renamed rdata field 'ip' to 'ipv4'
498*4b22b933Srs200217
499*4b22b933Srs200217 Revision 1.82 2004/09/16 21:36:36 cheshire
500*4b22b933Srs200217 <rdar://problem/3803162> Fix unsafe use of mDNSPlatformTimeNow()
501*4b22b933Srs200217 Changes to add necessary locking calls around unicast DNS operations
502*4b22b933Srs200217
503*4b22b933Srs200217 Revision 1.81 2004/09/16 02:29:39 cheshire
504*4b22b933Srs200217 Moved mDNS_Lock/mDNS_Unlock to DNSCommon.c; Added necessary locking around
505*4b22b933Srs200217 uDNS_ReceiveMsg, uDNS_StartQuery, uDNS_UpdateRecord, uDNS_RegisterService
506*4b22b933Srs200217
507*4b22b933Srs200217 Revision 1.80 2004/09/16 01:58:21 cheshire
508*4b22b933Srs200217 Fix compiler warnings
509*4b22b933Srs200217
510*4b22b933Srs200217 Revision 1.79 2004/09/16 00:24:48 cheshire
511*4b22b933Srs200217 <rdar://problem/3803162> Fix unsafe use of mDNSPlatformTimeNow()
512*4b22b933Srs200217
513*4b22b933Srs200217 Revision 1.78 2004/09/15 01:16:57 ksekar
514*4b22b933Srs200217 <rdar://problem/3797598> mDNSResponder printing too many messages
515*4b22b933Srs200217
516*4b22b933Srs200217 Revision 1.77 2004/09/14 23:27:47 cheshire
517*4b22b933Srs200217 Fix compile errors
518*4b22b933Srs200217
519*4b22b933Srs200217 Revision 1.76 2004/09/14 22:22:00 ksekar
520*4b22b933Srs200217 <rdar://problem/3800920> Legacy browses broken against some BIND versions
521*4b22b933Srs200217
522*4b22b933Srs200217 Revision 1.75 2004/09/03 19:23:05 ksekar
523*4b22b933Srs200217 <rdar://problem/3788460>: Need retransmission mechanism for wide-area service registrations
524*4b22b933Srs200217
525*4b22b933Srs200217 Revision 1.74 2004/09/02 17:49:04 ksekar
526*4b22b933Srs200217 <rdar://problem/3785135>: 8A246: mDNSResponder crash while logging on restart
527*4b22b933Srs200217 Fixed incorrect conversions, changed %s to %##s for all domain names.
528*4b22b933Srs200217
529*4b22b933Srs200217 Revision 1.73 2004/09/02 01:39:40 cheshire
530*4b22b933Srs200217 For better readability, follow consistent convention that QR bit comes first, followed by OP bits
531*4b22b933Srs200217
532*4b22b933Srs200217 Revision 1.72 2004/09/01 03:59:29 ksekar
533*4b22b933Srs200217 <rdar://problem/3783453>: Conditionally compile out uDNS code on Windows
534*4b22b933Srs200217
535*4b22b933Srs200217 Revision 1.71 2004/08/27 17:51:53 ksekar
536*4b22b933Srs200217 Replaced unnecessary LogMsg with debugf.
537*4b22b933Srs200217
538*4b22b933Srs200217 Revision 1.70 2004/08/25 00:37:27 ksekar
539*4b22b933Srs200217 <rdar://problem/3774635>: Cleanup DynDNS hostname registration code
540*4b22b933Srs200217
541*4b22b933Srs200217 Revision 1.69 2004/08/18 17:35:41 ksekar
542*4b22b933Srs200217 <rdar://problem/3651443>: Feature #9586: Need support for Legacy NAT gateways
543*4b22b933Srs200217
544*4b22b933Srs200217 Revision 1.68 2004/08/14 03:22:41 cheshire
545*4b22b933Srs200217 <rdar://problem/3762579> Dynamic DNS UI <-> mDNSResponder glue
546*4b22b933Srs200217 Add GetUserSpecifiedDDNSName() routine
547*4b22b933Srs200217 Convert ServiceRegDomain to domainname instead of C string
548*4b22b933Srs200217 Replace mDNS_GenerateFQDN/mDNS_GenerateGlobalFQDN with mDNS_SetFQDNs
549*4b22b933Srs200217
550*4b22b933Srs200217 Revision 1.67 2004/08/13 23:46:58 cheshire
551*4b22b933Srs200217 "asyncronous" -> "asynchronous"
552*4b22b933Srs200217
553*4b22b933Srs200217 Revision 1.66 2004/08/13 23:37:02 cheshire
554*4b22b933Srs200217 Now that we do both uDNS and mDNS, global replace "uDNS_info.hostname" with
555*4b22b933Srs200217 "uDNS_info.UnicastHostname" for clarity
556*4b22b933Srs200217
557*4b22b933Srs200217 Revision 1.65 2004/08/13 23:12:32 cheshire
558*4b22b933Srs200217 Don't use strcpy() and strlen() on "struct domainname" objects;
559*4b22b933Srs200217 use AssignDomainName() and DomainNameLength() instead
560*4b22b933Srs200217 (A "struct domainname" is a collection of packed pascal strings, not a C string.)
561*4b22b933Srs200217
562*4b22b933Srs200217 Revision 1.64 2004/08/13 23:01:05 cheshire
563*4b22b933Srs200217 Use platform-independent mDNSNULL instead of NULL
564*4b22b933Srs200217
565*4b22b933Srs200217 Revision 1.63 2004/08/12 00:32:36 ksekar
566*4b22b933Srs200217 <rdar://problem/3759567>: LLQ Refreshes never terminate if unanswered
567*4b22b933Srs200217
568*4b22b933Srs200217 Revision 1.62 2004/08/10 23:19:14 ksekar
569*4b22b933Srs200217 <rdar://problem/3722542>: DNS Extension daemon for Wide Area Service Discovery
570*4b22b933Srs200217 Moved routines/constants to allow extern access for garbage collection daemon
571*4b22b933Srs200217
572*4b22b933Srs200217 Revision 1.61 2004/07/30 17:40:06 ksekar
573*4b22b933Srs200217 <rdar://problem/3739115>: TXT Record updates not available for wide-area services
574*4b22b933Srs200217
575*4b22b933Srs200217 Revision 1.60 2004/07/29 19:40:05 ksekar
576*4b22b933Srs200217 NATPMP Support - minor fixes and cleanup
577*4b22b933Srs200217
578*4b22b933Srs200217 Revision 1.59 2004/07/29 19:27:15 ksekar
579*4b22b933Srs200217 NATPMP Support - minor fixes and cleanup
580*4b22b933Srs200217
581*4b22b933Srs200217 Revision 1.58 2004/07/27 07:35:38 shersche
582*4b22b933Srs200217 fix syntax error, variables declared in the middle of a block
583*4b22b933Srs200217
584*4b22b933Srs200217 Revision 1.57 2004/07/26 22:49:30 ksekar
585*4b22b933Srs200217 <rdar://problem/3651409>: Feature #9516: Need support for NATPMP in client
586*4b22b933Srs200217
587*4b22b933Srs200217 Revision 1.56 2004/07/26 19:14:44 ksekar
588*4b22b933Srs200217 <rdar://problem/3737814>: 8A210: mDNSResponder crashed in startLLQHandshakeCallback
589*4b22b933Srs200217
590*4b22b933Srs200217 Revision 1.55 2004/07/15 19:01:33 ksekar
591*4b22b933Srs200217 <rdar://problem/3681029>: Check for incorrect time comparisons
592*4b22b933Srs200217
593*4b22b933Srs200217 Revision 1.54 2004/06/22 02:10:53 ksekar
594*4b22b933Srs200217 <rdar://problem/3705433>: Lighthouse failure causes packet flood to DNS
595*4b22b933Srs200217
596*4b22b933Srs200217 Revision 1.53 2004/06/17 20:49:09 ksekar
597*4b22b933Srs200217 <rdar://problem/3690436>: mDNSResponder crash while location cycling
598*4b22b933Srs200217
599*4b22b933Srs200217 Revision 1.52 2004/06/17 01:13:11 ksekar
600*4b22b933Srs200217 <rdar://problem/3696616>: polling interval too short
601*4b22b933Srs200217
602*4b22b933Srs200217 Revision 1.51 2004/06/10 04:36:44 cheshire
603*4b22b933Srs200217 Fix compiler warning
604*4b22b933Srs200217
605*4b22b933Srs200217 Revision 1.50 2004/06/10 00:55:13 ksekar
606*4b22b933Srs200217 <rdar://problem/3686213>: crash on network reconnect
607*4b22b933Srs200217
608*4b22b933Srs200217 Revision 1.49 2004/06/10 00:10:50 ksekar
609*4b22b933Srs200217 <rdar://problem/3686174>: Infinite Loop in uDNS_Execute()
610*4b22b933Srs200217
611*4b22b933Srs200217 Revision 1.48 2004/06/09 20:03:37 ksekar
612*4b22b933Srs200217 <rdar://problem/3686163>: Incorrect copying of resource record in deregistration
613*4b22b933Srs200217
614*4b22b933Srs200217 Revision 1.47 2004/06/09 03:48:28 ksekar
615*4b22b933Srs200217 <rdar://problem/3685226>: nameserver address fails with prod. Lighthouse server
616*4b22b933Srs200217
617*4b22b933Srs200217 Revision 1.46 2004/06/09 01:44:30 ksekar
618*4b22b933Srs200217 <rdar://problem/3681378> reworked Cache Record copy code
619*4b22b933Srs200217
620*4b22b933Srs200217 Revision 1.45 2004/06/08 18:54:47 ksekar
621*4b22b933Srs200217 <rdar://problem/3681378>: mDNSResponder leaks after exploring in Printer Setup Utility
622*4b22b933Srs200217
623*4b22b933Srs200217 Revision 1.44 2004/06/05 00:33:51 cheshire
624*4b22b933Srs200217 <rdar://problem/3681029>: Check for incorrect time comparisons
625*4b22b933Srs200217
626*4b22b933Srs200217 Revision 1.43 2004/06/05 00:14:44 cheshire
627*4b22b933Srs200217 Fix signed/unsigned and other compiler warnings
628*4b22b933Srs200217
629*4b22b933Srs200217 Revision 1.42 2004/06/04 22:36:16 ksekar
630*4b22b933Srs200217 Properly set u->nextevent in uDNS_Execute
631*4b22b933Srs200217
632*4b22b933Srs200217 Revision 1.41 2004/06/04 08:58:29 ksekar
633*4b22b933Srs200217 <rdar://problem/3668624>: Keychain integration for secure dynamic update
634*4b22b933Srs200217
635*4b22b933Srs200217 Revision 1.40 2004/06/03 03:09:58 ksekar
636*4b22b933Srs200217 <rdar://problem/3668626>: Garbage Collection for Dynamic Updates
637*4b22b933Srs200217
638*4b22b933Srs200217 Revision 1.39 2004/06/01 23:46:50 ksekar
639*4b22b933Srs200217 <rdar://problem/3675149>: DynDNS: dynamically look up LLQ/Update ports
640*4b22b933Srs200217
641*4b22b933Srs200217 Revision 1.38 2004/05/31 22:19:44 ksekar
642*4b22b933Srs200217 <rdar://problem/3258021>: Feature: DNS server->client notification on
643*4b22b933Srs200217 record changes (#7805) - revert to polling mode on setup errors
644*4b22b933Srs200217
645*4b22b933Srs200217 Revision 1.37 2004/05/28 23:42:37 ksekar
646*4b22b933Srs200217 <rdar://problem/3258021>: Feature: DNS server->client notification on record changes (#7805)
647*4b22b933Srs200217
648*4b22b933Srs200217 Revision 1.36 2004/05/18 23:51:25 cheshire
649*4b22b933Srs200217 Tidy up all checkin comments to use consistent "<rdar://problem/xxxxxxx>" format for bug numbers
650*4b22b933Srs200217
651*4b22b933Srs200217 Revision 1.35 2004/05/07 23:01:04 ksekar
652*4b22b933Srs200217 Cleaned up list traversal in deriveGoodbyes - removed unnecessary
653*4b22b933Srs200217 conditional assignment.
654*4b22b933Srs200217
655*4b22b933Srs200217 Revision 1.34 2004/05/05 18:26:12 ksekar
656*4b22b933Srs200217 Periodically re-transmit questions if the send() fails. Include
657*4b22b933Srs200217 internal questions in retransmission.
658*4b22b933Srs200217
659*4b22b933Srs200217 Revision 1.33 2004/05/05 17:40:06 ksekar
660*4b22b933Srs200217 Removed prerequisite from deregistration update - it does not work for
661*4b22b933Srs200217 shared records, and is unnecessary until we have more sophisticated
662*4b22b933Srs200217 name conflict management.
663*4b22b933Srs200217
664*4b22b933Srs200217 Revision 1.32 2004/05/05 17:32:18 ksekar
665*4b22b933Srs200217 Prevent registration of loopback interface caused by removal of
666*4b22b933Srs200217 Multicast flag in interface structure.
667*4b22b933Srs200217
668*4b22b933Srs200217 Revision 1.31 2004/05/05 17:05:02 ksekar
669*4b22b933Srs200217 Use LargeCacheRecord structs when pulling records off packets
670*4b22b933Srs200217
671*4b22b933Srs200217 Revision 1.30 2004/04/16 21:33:27 ksekar
672*4b22b933Srs200217 Fixed bug in processing GetZoneData responses that do not use BIND formatting.
673*4b22b933Srs200217
674*4b22b933Srs200217 Revision 1.29 2004/04/15 20:03:13 ksekar
675*4b22b933Srs200217 Clarified log message when pulling bad resource records off packet.
676*4b22b933Srs200217
677*4b22b933Srs200217 Revision 1.28 2004/04/15 00:51:28 bradley
678*4b22b933Srs200217 Minor tweaks for Windows and C++ builds. Added casts for signed/unsigned integers and 64-bit pointers.
679*4b22b933Srs200217 Prefix some functions with mDNS to avoid conflicts. Disable benign warnings on Microsoft compilers.
680*4b22b933Srs200217
681*4b22b933Srs200217 Revision 1.27 2004/04/14 23:09:28 ksekar
682*4b22b933Srs200217 Support for TSIG signed dynamic updates.
683*4b22b933Srs200217
684*4b22b933Srs200217 Revision 1.26 2004/04/14 19:36:05 ksekar
685*4b22b933Srs200217 Fixed memory corruption error in deriveGoodbyes.
686*4b22b933Srs200217
687*4b22b933Srs200217 Revision 1.25 2004/04/14 04:07:11 ksekar
688*4b22b933Srs200217 Fixed crash in IsActiveUnicastQuery(). Removed redundant checks in routine.
689*4b22b933Srs200217
690*4b22b933Srs200217 Revision 1.24 2004/04/08 09:41:40 bradley
691*4b22b933Srs200217 Added const to AuthRecord in deadvertiseIfCallback to match callback typedef.
692*4b22b933Srs200217
693*4b22b933Srs200217 Revision 1.23 2004/03/24 00:29:45 ksekar
694*4b22b933Srs200217 Make it safe to call StopQuery in a unicast question callback
695*4b22b933Srs200217
696*4b22b933Srs200217 Revision 1.22 2004/03/19 10:11:09 bradley
697*4b22b933Srs200217 Added AuthRecord * cast from umalloc for C++ builds.
698*4b22b933Srs200217
699*4b22b933Srs200217 Revision 1.21 2004/03/15 02:03:45 bradley
700*4b22b933Srs200217 Added const to params where needed to match prototypes. Changed SetNewRData calls to use 0 instead
701*4b22b933Srs200217 of -1 for unused size to fix warning. Disable assignment within conditional warnings with Visual C++.
702*4b22b933Srs200217
703*4b22b933Srs200217 Revision 1.20 2004/03/13 02:07:26 ksekar
704*4b22b933Srs200217 <rdar://problem/3192546>: DynDNS: Dynamic update of service records
705*4b22b933Srs200217
706*4b22b933Srs200217 Revision 1.19 2004/03/13 01:57:33 ksekar
707*4b22b933Srs200217 <rdar://problem/3192546>: DynDNS: Dynamic update of service records
708*4b22b933Srs200217
709*4b22b933Srs200217 Revision 1.18 2004/02/21 08:34:15 bradley
710*4b22b933Srs200217 Added casts from void * to specific type for C++ builds. Changed void * l-value cast
711*4b22b933Srs200217 r-value cast to fix problems with VC++ builds. Removed empty switch to fix VC++ error.
712*4b22b933Srs200217
713*4b22b933Srs200217 Revision 1.17 2004/02/21 02:06:24 cheshire
714*4b22b933Srs200217 Can't use anonymous unions -- they're non-standard and don't work on all compilers
715*4b22b933Srs200217
716*4b22b933Srs200217 Revision 1.16 2004/02/12 01:51:45 cheshire
717*4b22b933Srs200217 Don't try to send uDNS queries unless we have at least one uDNS server available
718*4b22b933Srs200217
719*4b22b933Srs200217 Revision 1.15 2004/02/10 03:02:46 cheshire
720*4b22b933Srs200217 Fix compiler warning
721*4b22b933Srs200217
722*4b22b933Srs200217 Revision 1.14 2004/02/06 23:04:19 ksekar
723*4b22b933Srs200217 Basic Dynamic Update support via mDNS_Register (dissabled via
724*4b22b933Srs200217 UNICAST_REGISTRATION #define)
725*4b22b933Srs200217
726*4b22b933Srs200217 Revision 1.13 2004/02/03 22:15:01 ksekar
727*4b22b933Srs200217 Fixed nameToAddr error check: don't abort state machine on nxdomain error.
728*4b22b933Srs200217
729*4b22b933Srs200217 Revision 1.12 2004/02/03 19:47:36 ksekar
730*4b22b933Srs200217 Added an asynchronous state machine mechanism to uDNS.c, including
731*4b22b933Srs200217 calls to find the parent zone for a domain name. Changes include code
732*4b22b933Srs200217 in repository previously dissabled via "#if 0 incomplete". Codepath
733*4b22b933Srs200217 is currently unused, and will be called to create update records, etc.
734*4b22b933Srs200217
735*4b22b933Srs200217 Revision 1.11 2004/01/30 02:12:30 ksekar
736*4b22b933Srs200217 Changed uDNS_ReceiveMsg() to correctly return void.
737*4b22b933Srs200217
738*4b22b933Srs200217 Revision 1.10 2004/01/29 02:59:17 ksekar
739*4b22b933Srs200217 Unicast DNS: Changed from a resource record oriented question/response
740*4b22b933Srs200217 matching to packet based matching. New callback architecture allows
741*4b22b933Srs200217 collections of records in a response to be processed differently
742*4b22b933Srs200217 depending on the nature of the request, and allows the same structure
743*4b22b933Srs200217 to be used for internal and client-driven queries with different processing needs.
744*4b22b933Srs200217
745*4b22b933Srs200217 Revision 1.9 2004/01/28 20:20:45 ksekar
746*4b22b933Srs200217 Unified ActiveQueries and ActiveInternalQueries lists, using a flag to
747*4b22b933Srs200217 demux them. Check-in includes work-in-progress code, #ifdef'd out.
748*4b22b933Srs200217
749*4b22b933Srs200217 Revision 1.8 2004/01/28 02:30:07 ksekar
750*4b22b933Srs200217 Added default Search Domains to unicast browsing, controlled via
751*4b22b933Srs200217 Networking sharing prefs pane. Stopped sending unicast messages on
752*4b22b933Srs200217 every interface. Fixed unicast resolving via mach-port API.
753*4b22b933Srs200217
754*4b22b933Srs200217 Revision 1.7 2004/01/27 20:15:22 cheshire
755*4b22b933Srs200217 <rdar://problem/3541288>: Time to prune obsolete code for listening on port 53
756*4b22b933Srs200217
757*4b22b933Srs200217 Revision 1.6 2004/01/24 23:47:17 cheshire
758*4b22b933Srs200217 Use mDNSOpaque16fromIntVal() instead of shifting and masking
759*4b22b933Srs200217
760*4b22b933Srs200217 Revision 1.5 2004/01/24 04:59:15 cheshire
761*4b22b933Srs200217 Fixes so that Posix/Linux, OS9, Windows, and VxWorks targets build again
762*4b22b933Srs200217
763*4b22b933Srs200217 Revision 1.4 2004/01/24 04:19:26 cheshire
764*4b22b933Srs200217 Restore overwritten checkin 1.2
765*4b22b933Srs200217
766*4b22b933Srs200217 Revision 1.3 2004/01/23 23:23:15 ksekar
767*4b22b933Srs200217 Added TCP support for truncated unicast messages.
768*4b22b933Srs200217
769*4b22b933Srs200217 Revision 1.2 2004/01/22 03:48:41 cheshire
770*4b22b933Srs200217 Make sure uDNS client doesn't accidentally use query ID zero
771*4b22b933Srs200217
772*4b22b933Srs200217 Revision 1.1 2003/12/13 03:05:27 ksekar
773*4b22b933Srs200217 <rdar://problem/3192548>: DynDNS: Unicast query of service records
774*4b22b933Srs200217
775*4b22b933Srs200217 */
776*4b22b933Srs200217
777*4b22b933Srs200217 #pragma ident "%Z%%M% %I% %E% SMI"
778*4b22b933Srs200217
779*4b22b933Srs200217 #include "uDNS.h"
780*4b22b933Srs200217
781*4b22b933Srs200217 #if(defined(_MSC_VER))
782*4b22b933Srs200217 // Disable "assignment within conditional expression".
783*4b22b933Srs200217 // Other compilers understand the convention that if you place the assignment expression within an extra pair
784*4b22b933Srs200217 // of parentheses, this signals to the compiler that you really intended an assignment and no warning is necessary.
785*4b22b933Srs200217 // The Microsoft compiler doesn't understand this convention, so in the absense of any other way to signal
786*4b22b933Srs200217 // to the compiler that the assignment is intentional, we have to just turn this warning off completely.
787*4b22b933Srs200217 #pragma warning(disable:4706)
788*4b22b933Srs200217 #endif
789*4b22b933Srs200217
790*4b22b933Srs200217 #define umalloc(x) mDNSPlatformMemAllocate(x) // short hands for common routines
791*4b22b933Srs200217 #define ufree(x) mDNSPlatformMemFree(x)
792*4b22b933Srs200217 #define ubzero(x,y) mDNSPlatformMemZero(x,y)
793*4b22b933Srs200217 #define umemcpy(x, y, l) mDNSPlatformMemCopy(y, x, l) // uses memcpy(2) arg ordering
794*4b22b933Srs200217
795*4b22b933Srs200217 // Asynchronous operation types
796*4b22b933Srs200217
797*4b22b933Srs200217 typedef enum
798*4b22b933Srs200217 {
799*4b22b933Srs200217 zoneDataResult
800*4b22b933Srs200217 // other async. operation names go here
801*4b22b933Srs200217 } AsyncOpResultType;
802*4b22b933Srs200217
803*4b22b933Srs200217 typedef struct
804*4b22b933Srs200217 {
805*4b22b933Srs200217 domainname zoneName;
806*4b22b933Srs200217 mDNSAddr primaryAddr;
807*4b22b933Srs200217 mDNSu16 zoneClass;
808*4b22b933Srs200217 mDNSIPPort llqPort;
809*4b22b933Srs200217 mDNSIPPort updatePort;
810*4b22b933Srs200217 } zoneData_t;
811*4b22b933Srs200217
812*4b22b933Srs200217 // other async. result struct defs go here
813*4b22b933Srs200217
814*4b22b933Srs200217 typedef struct
815*4b22b933Srs200217 {
816*4b22b933Srs200217 AsyncOpResultType type;
817*4b22b933Srs200217 zoneData_t zoneData;
818*4b22b933Srs200217 // other async result structs go here
819*4b22b933Srs200217 } AsyncOpResult;
820*4b22b933Srs200217
821*4b22b933Srs200217 typedef void AsyncOpCallback(mStatus err, mDNS *const m, void *info, const AsyncOpResult *result);
822*4b22b933Srs200217
823*4b22b933Srs200217
824*4b22b933Srs200217 // Private Function Prototypes
825*4b22b933Srs200217 // Note: In general, functions are ordered such that they do not require forward declarations.
826*4b22b933Srs200217 // However, prototypes are used where cyclic call graphs exist (e.g. foo calls bar, and bar calls
827*4b22b933Srs200217 // foo), or when they aid in the grouping or readability of code (e.g. state machine code that is easier
828*4b22b933Srs200217 // read top-to-bottom.)
829*4b22b933Srs200217
830*4b22b933Srs200217 mDNSlocal mDNSBool FreeNATInfo(mDNS *m, NATTraversalInfo *n);
831*4b22b933Srs200217 mDNSlocal void hndlTruncatedAnswer(DNSQuestion *question, const mDNSAddr *src, mDNS *m);
832*4b22b933Srs200217 mDNSlocal mStatus startGetZoneData(domainname *name, mDNS *m, mDNSBool findUpdatePort, mDNSBool findLLQPort, AsyncOpCallback callback, void *callbackInfo);
833*4b22b933Srs200217 mDNSlocal mDNSBool recvLLQResponse(mDNS *m, DNSMessage *msg, const mDNSu8 *end, const mDNSAddr *srcaddr, mDNSIPPort srcport, const mDNSInterfaceID InterfaceID);
834*4b22b933Srs200217 mDNSlocal void sendRecordRegistration(mDNS *const m, AuthRecord *rr);
835*4b22b933Srs200217 mDNSlocal void SendServiceRegistration(mDNS *m, ServiceRecordSet *srs);
836*4b22b933Srs200217 mDNSlocal void SendServiceDeregistration(mDNS *m, ServiceRecordSet *srs);
837*4b22b933Srs200217 mDNSlocal void serviceRegistrationCallback(mStatus err, mDNS *const m, void *srsPtr, const AsyncOpResult *result);
838*4b22b933Srs200217 mDNSlocal void SuspendLLQs(mDNS *m, mDNSBool DeregisterActive);
839*4b22b933Srs200217 mDNSlocal void RestartQueries(mDNS *m);
840*4b22b933Srs200217 mDNSlocal void startLLQHandshake(mDNS *m, LLQ_Info *info, mDNSBool defer);
841*4b22b933Srs200217 mDNSlocal void llqResponseHndlr(mDNS * const m, DNSMessage *msg, const mDNSu8 *end, DNSQuestion *question, void *context);
842*4b22b933Srs200217
843*4b22b933Srs200217 // ***************************************************************************
844*4b22b933Srs200217 #if COMPILER_LIKES_PRAGMA_MARK
845*4b22b933Srs200217 #pragma mark - Temporary workaround
846*4b22b933Srs200217 #endif
847*4b22b933Srs200217
848*4b22b933Srs200217 // 17 Places in this file directly call mDNSPlatformTimeNow(), which is unsafe
849*4b22b933Srs200217 // The platform function is now called mDNSPlatformRawTime(), and
850*4b22b933Srs200217 // mDNSPlatformTimeNow() is defined here as a temporary workaround.
851*4b22b933Srs200217 // This is a gross hack, and after this change has been tested for a while,
852*4b22b933Srs200217 // all these calls should be replaced by simple references to m->timenow
853*4b22b933Srs200217
mDNSPlatformTimeNow(mDNS * m)854*4b22b933Srs200217 mDNSlocal mDNSs32 mDNSPlatformTimeNow(mDNS *m)
855*4b22b933Srs200217 {
856*4b22b933Srs200217 if (m->mDNS_busy && m->timenow) return(m->timenow);
857*4b22b933Srs200217 LogMsg("ERROR: uDNS.c code executing without holding main mDNS lock");
858*4b22b933Srs200217
859*4b22b933Srs200217 // To get a quick and easy stack trace to find out *how* this routine
860*4b22b933Srs200217 // is being called without holding main mDNS lock, uncomment the line below:
861*4b22b933Srs200217 // *(long*)0=0;
862*4b22b933Srs200217
863*4b22b933Srs200217 return(mDNS_TimeNow(m));
864*4b22b933Srs200217 }
865*4b22b933Srs200217
866*4b22b933Srs200217 // ***************************************************************************
867*4b22b933Srs200217 #if COMPILER_LIKES_PRAGMA_MARK
868*4b22b933Srs200217 #pragma mark - General Utility Functions
869*4b22b933Srs200217 #endif
870*4b22b933Srs200217
871*4b22b933Srs200217 // CountLabels() returns number of labels in name, excluding final root label
872*4b22b933Srs200217 // (e.g. for "apple.com." CountLabels returns 2.)
CountLabels(const domainname * d)873*4b22b933Srs200217 mDNSlocal int CountLabels(const domainname *d)
874*4b22b933Srs200217 {
875*4b22b933Srs200217 int count = 0;
876*4b22b933Srs200217 const mDNSu8 *ptr;
877*4b22b933Srs200217
878*4b22b933Srs200217 for (ptr = d->c; *ptr; ptr = ptr + ptr[0] + 1) count++;
879*4b22b933Srs200217 return count;
880*4b22b933Srs200217 }
881*4b22b933Srs200217
newMessageID(uDNS_GlobalInfo * u)882*4b22b933Srs200217 mDNSlocal mDNSOpaque16 newMessageID(uDNS_GlobalInfo *u)
883*4b22b933Srs200217 {
884*4b22b933Srs200217 static mDNSBool randomized = mDNSfalse;
885*4b22b933Srs200217
886*4b22b933Srs200217 if (!randomized) { u->NextMessageID = (mDNSu16)mDNSRandom(0xFFFF); randomized = mDNStrue; }
887*4b22b933Srs200217 if (u->NextMessageID == 0) u->NextMessageID++;
888*4b22b933Srs200217 return mDNSOpaque16fromIntVal(u->NextMessageID++);
889*4b22b933Srs200217 }
890*4b22b933Srs200217
891*4b22b933Srs200217 // unlink an AuthRecord from a linked list
unlinkAR(AuthRecord ** list,AuthRecord * const rr)892*4b22b933Srs200217 mDNSlocal mStatus unlinkAR(AuthRecord **list, AuthRecord *const rr)
893*4b22b933Srs200217 {
894*4b22b933Srs200217 while (*list && *list != rr) list = &(*list)->next;
895*4b22b933Srs200217 if (*list) { *list = rr->next; rr->next = mDNSNULL; return(mStatus_NoError); }
896*4b22b933Srs200217 LogMsg("ERROR: unlinkAR - no such active record %##s", rr->resrec.name->c);
897*4b22b933Srs200217 return(mStatus_NoSuchRecord);
898*4b22b933Srs200217 }
899*4b22b933Srs200217
unlinkSRS(mDNS * m,ServiceRecordSet * srs)900*4b22b933Srs200217 mDNSlocal void unlinkSRS(mDNS *m, ServiceRecordSet *srs)
901*4b22b933Srs200217 {
902*4b22b933Srs200217 uDNS_GlobalInfo *u = &m->uDNS_info;
903*4b22b933Srs200217 ServiceRecordSet **p;
904*4b22b933Srs200217 NATTraversalInfo *n = u->NATTraversals;
905*4b22b933Srs200217
906*4b22b933Srs200217 // verify that no NAT objects reference this service
907*4b22b933Srs200217 while (n)
908*4b22b933Srs200217 {
909*4b22b933Srs200217 if (n->reg.ServiceRegistration == srs)
910*4b22b933Srs200217 {
911*4b22b933Srs200217 NATTraversalInfo *tmp = n;
912*4b22b933Srs200217 n = n->next;
913*4b22b933Srs200217 LogMsg("ERROR: Unlinking service record set %##s still referenced by NAT traversal object!", srs->RR_SRV.resrec.name->c);
914*4b22b933Srs200217 FreeNATInfo(m, tmp);
915*4b22b933Srs200217 }
916*4b22b933Srs200217 else n = n->next;
917*4b22b933Srs200217 }
918*4b22b933Srs200217
919*4b22b933Srs200217 for (p = &u->ServiceRegistrations; *p; p = &(*p)->next)
920*4b22b933Srs200217 if (*p == srs)
921*4b22b933Srs200217 {
922*4b22b933Srs200217 ExtraResourceRecord *e;
923*4b22b933Srs200217 *p = srs->next;
924*4b22b933Srs200217 srs->next = mDNSNULL;
925*4b22b933Srs200217 for (e=srs->Extras; e; e=e->next)
926*4b22b933Srs200217 if (unlinkAR(&u->RecordRegistrations, &e->r))
927*4b22b933Srs200217 LogMsg("unlinkSRS: extra record %##s not found", e->r.resrec.name->c);
928*4b22b933Srs200217 return;
929*4b22b933Srs200217 }
930*4b22b933Srs200217 LogMsg("ERROR: unlinkSRS - SRS not found in ServiceRegistrations list %##s", srs->RR_SRV.resrec.name->c);
931*4b22b933Srs200217 }
932*4b22b933Srs200217
LinkActiveQuestion(uDNS_GlobalInfo * u,DNSQuestion * q)933*4b22b933Srs200217 mDNSlocal void LinkActiveQuestion(uDNS_GlobalInfo *u, DNSQuestion *q)
934*4b22b933Srs200217 {
935*4b22b933Srs200217 if (uDNS_IsActiveQuery(q, u))
936*4b22b933Srs200217 { LogMsg("LinkActiveQuestion - %##s (%d) already in list!", q->qname.c, q->qtype); return; }
937*4b22b933Srs200217
938*4b22b933Srs200217 q->next = u->ActiveQueries;
939*4b22b933Srs200217 u->ActiveQueries = q;
940*4b22b933Srs200217 }
941*4b22b933Srs200217
942*4b22b933Srs200217 // set retry timestamp for record with exponential backoff
943*4b22b933Srs200217 // (for service record sets, use RR_SRV as representative for time checks
SetRecordRetry(mDNS * const m,AuthRecord * rr,mStatus SendErr)944*4b22b933Srs200217 mDNSlocal void SetRecordRetry(mDNS *const m, AuthRecord *rr, mStatus SendErr)
945*4b22b933Srs200217 {
946*4b22b933Srs200217 rr->LastAPTime = mDNSPlatformTimeNow(m);
947*4b22b933Srs200217 if (SendErr == mStatus_TransientErr || rr->ThisAPInterval < INIT_UCAST_POLL_INTERVAL) rr->ThisAPInterval = INIT_UCAST_POLL_INTERVAL;
948*4b22b933Srs200217 else if (rr->ThisAPInterval*2 <= MAX_UCAST_POLL_INTERVAL) rr->ThisAPInterval *= 2;
949*4b22b933Srs200217 else if (rr->ThisAPInterval != MAX_UCAST_POLL_INTERVAL) rr->ThisAPInterval = MAX_UCAST_POLL_INTERVAL;
950*4b22b933Srs200217 }
951*4b22b933Srs200217
952*4b22b933Srs200217
953*4b22b933Srs200217 // ***************************************************************************
954*4b22b933Srs200217 #if COMPILER_LIKES_PRAGMA_MARK
955*4b22b933Srs200217 #pragma mark - Name Server List Management
956*4b22b933Srs200217 #endif
957*4b22b933Srs200217
mDNS_AddDNSServer(mDNS * const m,const mDNSAddr * addr,const domainname * d)958*4b22b933Srs200217 mDNSexport void mDNS_AddDNSServer(mDNS *const m, const mDNSAddr *addr, const domainname *d)
959*4b22b933Srs200217 {
960*4b22b933Srs200217 uDNS_GlobalInfo *u = &m->uDNS_info;
961*4b22b933Srs200217 DNSServer *s, **p = &u->Servers;
962*4b22b933Srs200217
963*4b22b933Srs200217 mDNS_Lock(m);
964*4b22b933Srs200217 if (!d) d = (domainname *)"";
965*4b22b933Srs200217
966*4b22b933Srs200217 while (*p) // Check if we already have this {server,domain} pair registered
967*4b22b933Srs200217 {
968*4b22b933Srs200217 if (mDNSSameAddress(&(*p)->addr, addr) && SameDomainName(&(*p)->domain, d))
969*4b22b933Srs200217 LogMsg("Note: DNS Server %#a for domain %##s registered more than once", addr, d->c);
970*4b22b933Srs200217 p=&(*p)->next;
971*4b22b933Srs200217 }
972*4b22b933Srs200217
973*4b22b933Srs200217 // allocate, add to list
974*4b22b933Srs200217 s = umalloc(sizeof(*s));
975*4b22b933Srs200217 if (!s) { LogMsg("Error: mDNS_AddDNSServer - malloc"); goto end; }
976*4b22b933Srs200217 s->addr = *addr;
977*4b22b933Srs200217 s->del = mDNSfalse;
978*4b22b933Srs200217 s->teststate = DNSServer_Untested;
979*4b22b933Srs200217 AssignDomainName(&s->domain, d);
980*4b22b933Srs200217 s->next = mDNSNULL;
981*4b22b933Srs200217 *p = s;
982*4b22b933Srs200217
983*4b22b933Srs200217 end:
984*4b22b933Srs200217 mDNS_Unlock(m);
985*4b22b933Srs200217 }
986*4b22b933Srs200217
mDNS_DeleteDNSServers(mDNS * const m)987*4b22b933Srs200217 mDNSexport void mDNS_DeleteDNSServers(mDNS *const m)
988*4b22b933Srs200217 {
989*4b22b933Srs200217 DNSServer *s;
990*4b22b933Srs200217 mDNS_Lock(m);
991*4b22b933Srs200217
992*4b22b933Srs200217 s = m->uDNS_info.Servers;
993*4b22b933Srs200217 m->uDNS_info.Servers = mDNSNULL;
994*4b22b933Srs200217 while (s)
995*4b22b933Srs200217 {
996*4b22b933Srs200217 DNSServer *tmp = s;
997*4b22b933Srs200217 s = s->next;
998*4b22b933Srs200217 ufree(tmp);
999*4b22b933Srs200217 }
1000*4b22b933Srs200217
1001*4b22b933Srs200217 mDNS_Unlock(m);
1002*4b22b933Srs200217 }
1003*4b22b933Srs200217
1004*4b22b933Srs200217 // ***************************************************************************
1005*4b22b933Srs200217 #if COMPILER_LIKES_PRAGMA_MARK
1006*4b22b933Srs200217 #pragma mark - authorization management
1007*4b22b933Srs200217 #endif
1008*4b22b933Srs200217
GetAuthInfoForName(const uDNS_GlobalInfo * u,const domainname * name)1009*4b22b933Srs200217 mDNSlocal uDNS_AuthInfo *GetAuthInfoForName(const uDNS_GlobalInfo *u, const domainname *name)
1010*4b22b933Srs200217 {
1011*4b22b933Srs200217 uDNS_AuthInfo *ptr;
1012*4b22b933Srs200217 while (name->c[0])
1013*4b22b933Srs200217 {
1014*4b22b933Srs200217 for (ptr = u->AuthInfoList; ptr; ptr = ptr->next)
1015*4b22b933Srs200217 if (SameDomainName(&ptr->zone, name)) return(ptr);
1016*4b22b933Srs200217 name = (const domainname *)(name->c + 1 + name->c[0]);
1017*4b22b933Srs200217 }
1018*4b22b933Srs200217 return mDNSNULL;
1019*4b22b933Srs200217 }
1020*4b22b933Srs200217
DeleteAuthInfoForZone(uDNS_GlobalInfo * u,const domainname * zone)1021*4b22b933Srs200217 mDNSlocal void DeleteAuthInfoForZone(uDNS_GlobalInfo *u, const domainname *zone)
1022*4b22b933Srs200217 {
1023*4b22b933Srs200217 uDNS_AuthInfo *ptr, *prev = mDNSNULL;
1024*4b22b933Srs200217
1025*4b22b933Srs200217 for (ptr = u->AuthInfoList; ptr; ptr = ptr->next)
1026*4b22b933Srs200217 {
1027*4b22b933Srs200217 if (SameDomainName(&ptr->zone, zone))
1028*4b22b933Srs200217 {
1029*4b22b933Srs200217 if (prev) prev->next = ptr->next;
1030*4b22b933Srs200217 else u->AuthInfoList = ptr->next;
1031*4b22b933Srs200217 ufree(ptr);
1032*4b22b933Srs200217 return;
1033*4b22b933Srs200217 }
1034*4b22b933Srs200217 prev = ptr;
1035*4b22b933Srs200217 }
1036*4b22b933Srs200217 }
1037*4b22b933Srs200217
mDNS_SetSecretForZone(mDNS * m,const domainname * zone,const domainname * key,const char * sharedSecret)1038*4b22b933Srs200217 mDNSexport mStatus mDNS_SetSecretForZone(mDNS *m, const domainname *zone, const domainname *key, const char *sharedSecret)
1039*4b22b933Srs200217 {
1040*4b22b933Srs200217 uDNS_AuthInfo *info;
1041*4b22b933Srs200217 mDNSu8 keybuf[1024];
1042*4b22b933Srs200217 mDNSs32 keylen;
1043*4b22b933Srs200217 uDNS_GlobalInfo *u = &m->uDNS_info;
1044*4b22b933Srs200217 mStatus status = mStatus_NoError;
1045*4b22b933Srs200217
1046*4b22b933Srs200217 mDNS_Lock(m);
1047*4b22b933Srs200217
1048*4b22b933Srs200217 if (GetAuthInfoForName(u, zone)) DeleteAuthInfoForZone(u, zone);
1049*4b22b933Srs200217 if (!key) goto exit;
1050*4b22b933Srs200217
1051*4b22b933Srs200217 info = (uDNS_AuthInfo*)umalloc(sizeof(*info));
1052*4b22b933Srs200217 if (!info) { LogMsg("ERROR: umalloc"); status = mStatus_NoMemoryErr; goto exit; }
1053*4b22b933Srs200217 ubzero(info, sizeof(*info));
1054*4b22b933Srs200217 AssignDomainName(&info->zone, zone);
1055*4b22b933Srs200217 AssignDomainName(&info->keyname, key);
1056*4b22b933Srs200217
1057*4b22b933Srs200217 keylen = DNSDigest_Base64ToBin(sharedSecret, keybuf, 1024);
1058*4b22b933Srs200217 if (keylen < 0)
1059*4b22b933Srs200217 {
1060*4b22b933Srs200217 LogMsg("ERROR: mDNS_SetSecretForZone - could not convert shared secret %s from base64", sharedSecret);
1061*4b22b933Srs200217 ufree(info);
1062*4b22b933Srs200217 status = mStatus_UnknownErr;
1063*4b22b933Srs200217 goto exit;
1064*4b22b933Srs200217 }
1065*4b22b933Srs200217 DNSDigest_ConstructHMACKey(info, keybuf, (mDNSu32)keylen);
1066*4b22b933Srs200217
1067*4b22b933Srs200217 // link into list
1068*4b22b933Srs200217 info->next = m->uDNS_info.AuthInfoList;
1069*4b22b933Srs200217 m->uDNS_info.AuthInfoList = info;
1070*4b22b933Srs200217 exit:
1071*4b22b933Srs200217 mDNS_Unlock(m);
1072*4b22b933Srs200217 return status;
1073*4b22b933Srs200217 }
1074*4b22b933Srs200217
1075*4b22b933Srs200217 // ***************************************************************************
1076*4b22b933Srs200217 #if COMPILER_LIKES_PRAGMA_MARK
1077*4b22b933Srs200217 #pragma mark - NAT Traversal
1078*4b22b933Srs200217 #endif
1079*4b22b933Srs200217
DomainContainsLabelString(const domainname * d,const char * str)1080*4b22b933Srs200217 mDNSlocal mDNSBool DomainContainsLabelString(const domainname *d, const char *str)
1081*4b22b933Srs200217 {
1082*4b22b933Srs200217 const domainlabel *l;
1083*4b22b933Srs200217 domainlabel buf;
1084*4b22b933Srs200217
1085*4b22b933Srs200217 if (!MakeDomainLabelFromLiteralString(&buf, str)) return mDNSfalse;
1086*4b22b933Srs200217
1087*4b22b933Srs200217 for (l = (const domainlabel *)d; l->c[0]; l = (const domainlabel *)(l->c + l->c[0]+1))
1088*4b22b933Srs200217 if (SameDomainLabel(l->c, buf.c)) return mDNStrue;
1089*4b22b933Srs200217 return mDNSfalse;
1090*4b22b933Srs200217 }
1091*4b22b933Srs200217
1092*4b22b933Srs200217 // allocate struct, link into global list, initialize
AllocNATInfo(mDNS * const m,NATOp_t op,NATResponseHndlr callback)1093*4b22b933Srs200217 mDNSlocal NATTraversalInfo *AllocNATInfo(mDNS *const m, NATOp_t op, NATResponseHndlr callback)
1094*4b22b933Srs200217 {
1095*4b22b933Srs200217 uDNS_GlobalInfo *u = &m->uDNS_info;
1096*4b22b933Srs200217 NATTraversalInfo *info = umalloc(sizeof(NATTraversalInfo));
1097*4b22b933Srs200217 if (!info) { LogMsg("ERROR: malloc"); return mDNSNULL; }
1098*4b22b933Srs200217 ubzero(info, sizeof(NATTraversalInfo));
1099*4b22b933Srs200217 info->next = u->NATTraversals;
1100*4b22b933Srs200217 u->NATTraversals = info;
1101*4b22b933Srs200217 info->retry = mDNSPlatformTimeNow(m) + NATMAP_INIT_RETRY;
1102*4b22b933Srs200217 info->op = op;
1103*4b22b933Srs200217 info->state = NATState_Init;
1104*4b22b933Srs200217 info->ReceiveResponse = callback;
1105*4b22b933Srs200217 info->PublicPort.NotAnInteger = 0;
1106*4b22b933Srs200217 info->Router = u->Router;
1107*4b22b933Srs200217 return info;
1108*4b22b933Srs200217 }
1109*4b22b933Srs200217
1110*4b22b933Srs200217 // unlink from list, deallocate
FreeNATInfo(mDNS * m,NATTraversalInfo * n)1111*4b22b933Srs200217 mDNSlocal mDNSBool FreeNATInfo(mDNS *m, NATTraversalInfo *n)
1112*4b22b933Srs200217 {
1113*4b22b933Srs200217 NATTraversalInfo *ptr, *prev = mDNSNULL;
1114*4b22b933Srs200217 ServiceRecordSet *s = m->uDNS_info.ServiceRegistrations;
1115*4b22b933Srs200217
1116*4b22b933Srs200217 // Verify that object is not referenced by any services
1117*4b22b933Srs200217 while (s)
1118*4b22b933Srs200217 {
1119*4b22b933Srs200217 if (s->uDNS_info.NATinfo == n)
1120*4b22b933Srs200217 {
1121*4b22b933Srs200217 LogMsg("Error: Freeing NAT info object still referenced by Service Record Set %##s!", s->RR_SRV.resrec.name->c);
1122*4b22b933Srs200217 s->uDNS_info.NATinfo = mDNSNULL;
1123*4b22b933Srs200217 }
1124*4b22b933Srs200217 s = s->next;
1125*4b22b933Srs200217 }
1126*4b22b933Srs200217
1127*4b22b933Srs200217 if (n == m->uDNS_info.LLQNatInfo) m->uDNS_info.LLQNatInfo = mDNSNULL;
1128*4b22b933Srs200217 ptr = m->uDNS_info.NATTraversals;
1129*4b22b933Srs200217 while (ptr)
1130*4b22b933Srs200217 {
1131*4b22b933Srs200217 if (ptr == n)
1132*4b22b933Srs200217 {
1133*4b22b933Srs200217 if (prev) prev->next = ptr->next;
1134*4b22b933Srs200217 else m->uDNS_info.NATTraversals = ptr->next;
1135*4b22b933Srs200217 ufree(n);
1136*4b22b933Srs200217 return mDNStrue;
1137*4b22b933Srs200217 }
1138*4b22b933Srs200217 prev = ptr;
1139*4b22b933Srs200217 ptr = ptr->next;
1140*4b22b933Srs200217 }
1141*4b22b933Srs200217 LogMsg("FreeNATInfo: NATTraversalInfo not found in list");
1142*4b22b933Srs200217 return mDNSfalse;
1143*4b22b933Srs200217 }
1144*4b22b933Srs200217
SendNATMsg(NATTraversalInfo * info,mDNS * m)1145*4b22b933Srs200217 mDNSlocal void SendNATMsg(NATTraversalInfo *info, mDNS *m)
1146*4b22b933Srs200217 {
1147*4b22b933Srs200217 mStatus err;
1148*4b22b933Srs200217 uDNS_GlobalInfo *u = &m->uDNS_info;
1149*4b22b933Srs200217
1150*4b22b933Srs200217 if (info->state != NATState_Request && info->state != NATState_Refresh)
1151*4b22b933Srs200217 { LogMsg("SendNATMsg: Bad state %d", info->state); return; }
1152*4b22b933Srs200217
1153*4b22b933Srs200217 if (u->Router.ip.v4.NotAnInteger)
1154*4b22b933Srs200217 {
1155*4b22b933Srs200217 // send msg if we have a router
1156*4b22b933Srs200217 const mDNSu8 *end = (mDNSu8 *)&info->request;
1157*4b22b933Srs200217 if (info->op == NATOp_AddrRequest) end += sizeof(NATAddrRequest);
1158*4b22b933Srs200217 else end += sizeof(NATPortMapRequest);
1159*4b22b933Srs200217
1160*4b22b933Srs200217 err = mDNSPlatformSendUDP(m, &info->request, end, 0, &u->Router, NATPMPPort);
1161*4b22b933Srs200217 if (!err) (info->ntries++); // don't increment attempt counter if the send failed
1162*4b22b933Srs200217 }
1163*4b22b933Srs200217
1164*4b22b933Srs200217 // set retry
1165*4b22b933Srs200217 if (info->RetryInterval < NATMAP_INIT_RETRY) info->RetryInterval = NATMAP_INIT_RETRY;
1166*4b22b933Srs200217 else if (info->RetryInterval * 2 > NATMAP_MAX_RETRY) info->RetryInterval = NATMAP_MAX_RETRY;
1167*4b22b933Srs200217 else info->RetryInterval *= 2;
1168*4b22b933Srs200217 info->retry = mDNSPlatformTimeNow(m) + info->RetryInterval;
1169*4b22b933Srs200217 }
1170*4b22b933Srs200217
ReceiveNATAddrResponse(NATTraversalInfo * n,mDNS * m,mDNSu8 * pkt,mDNSu16 len)1171*4b22b933Srs200217 mDNSlocal mDNSBool ReceiveNATAddrResponse(NATTraversalInfo *n, mDNS *m, mDNSu8 *pkt, mDNSu16 len)
1172*4b22b933Srs200217 {
1173*4b22b933Srs200217 mStatus err = mStatus_NoError;
1174*4b22b933Srs200217 AuthRecord *rr = mDNSNULL;
1175*4b22b933Srs200217 NATAddrReply *response = (NATAddrReply *)pkt;
1176*4b22b933Srs200217 mDNSAddr addr;
1177*4b22b933Srs200217
1178*4b22b933Srs200217 if (n->state != NATState_Request)
1179*4b22b933Srs200217 {
1180*4b22b933Srs200217 LogMsg("ReceiveNATAddrResponse: bad state %d", n->state);
1181*4b22b933Srs200217 return mDNSfalse;
1182*4b22b933Srs200217 }
1183*4b22b933Srs200217
1184*4b22b933Srs200217 rr = n->reg.RecordRegistration;
1185*4b22b933Srs200217 if (!rr)
1186*4b22b933Srs200217 {
1187*4b22b933Srs200217 LogMsg("ReceiveNATAddrResponse: registration cancelled");
1188*4b22b933Srs200217 return mDNSfalse;
1189*4b22b933Srs200217 }
1190*4b22b933Srs200217
1191*4b22b933Srs200217 addr.type = mDNSAddrType_IPv4;
1192*4b22b933Srs200217 addr.ip.v4 = rr->resrec.rdata->u.ipv4;
1193*4b22b933Srs200217
1194*4b22b933Srs200217 if (!pkt) // timeout
1195*4b22b933Srs200217 {
1196*4b22b933Srs200217 #ifdef _LEGACY_NAT_TRAVERSAL_
1197*4b22b933Srs200217 err = LNT_GetPublicIP(&addr.ip.v4);
1198*4b22b933Srs200217 if (err) goto end;
1199*4b22b933Srs200217 else n->state = NATState_Legacy;
1200*4b22b933Srs200217 #else
1201*4b22b933Srs200217 debugf("ReceiveNATAddrResponse: timeout");
1202*4b22b933Srs200217 err = mStatus_NATTraversal;
1203*4b22b933Srs200217 goto end;
1204*4b22b933Srs200217 #endif // _LEGACY_NAT_TRAVERSAL_
1205*4b22b933Srs200217 }
1206*4b22b933Srs200217 else
1207*4b22b933Srs200217 {
1208*4b22b933Srs200217 if (len < sizeof(*response))
1209*4b22b933Srs200217 {
1210*4b22b933Srs200217 LogMsg("ReceiveNATAddrResponse: response too short (%d bytes)", len);
1211*4b22b933Srs200217 return mDNSfalse;
1212*4b22b933Srs200217 }
1213*4b22b933Srs200217 if (response->vers != NATMAP_VERS)
1214*4b22b933Srs200217 {
1215*4b22b933Srs200217 LogMsg("ReceiveNATAddrResponse: received version %d (expect version %d)", pkt[0], NATMAP_VERS);
1216*4b22b933Srs200217 return mDNSfalse;
1217*4b22b933Srs200217 }
1218*4b22b933Srs200217 if (response->opcode != (NATOp_AddrRequest | NATMAP_RESPONSE_MASK))
1219*4b22b933Srs200217 {
1220*4b22b933Srs200217 LogMsg("ReceiveNATAddrResponse: bad response code %d", response->opcode);
1221*4b22b933Srs200217 return mDNSfalse;
1222*4b22b933Srs200217 }
1223*4b22b933Srs200217 if (response->err.NotAnInteger)
1224*4b22b933Srs200217 { LogMsg("ReceiveAddrResponse: received error %d", mDNSVal16(response->err)); err = mStatus_NATTraversal; goto end; }
1225*4b22b933Srs200217
1226*4b22b933Srs200217 addr.ip.v4 = response->PubAddr;
1227*4b22b933Srs200217 n->state = NATState_Established;
1228*4b22b933Srs200217 }
1229*4b22b933Srs200217
1230*4b22b933Srs200217 if (IsPrivateV4Addr(&addr))
1231*4b22b933Srs200217 {
1232*4b22b933Srs200217 LogMsg("ReceiveNATAddrResponse: Double NAT");
1233*4b22b933Srs200217 err = mStatus_DoubleNAT;
1234*4b22b933Srs200217 goto end;
1235*4b22b933Srs200217 }
1236*4b22b933Srs200217
1237*4b22b933Srs200217 end:
1238*4b22b933Srs200217 if (err)
1239*4b22b933Srs200217 {
1240*4b22b933Srs200217 FreeNATInfo(m, n);
1241*4b22b933Srs200217 if (rr)
1242*4b22b933Srs200217 {
1243*4b22b933Srs200217 rr->uDNS_info.NATinfo = mDNSNULL;
1244*4b22b933Srs200217 rr->uDNS_info.state = regState_Unregistered; // note that rr is not yet in global list
1245*4b22b933Srs200217 rr->RecordCallback(m, rr, mStatus_NATTraversal);
1246*4b22b933Srs200217 // note - unsafe to touch rr after callback
1247*4b22b933Srs200217 }
1248*4b22b933Srs200217 return mDNStrue;
1249*4b22b933Srs200217 }
1250*4b22b933Srs200217 else LogOperation("Received public IP address %d.%d.%d.%d from NAT.", addr.ip.v4.b[0], addr.ip.v4.b[1], addr.ip.v4.b[2], addr.ip.v4.b[3]);
1251*4b22b933Srs200217 rr->resrec.rdata->u.ipv4 = addr.ip.v4; // replace rdata w/ public address
1252*4b22b933Srs200217 uDNS_RegisterRecord(m, rr);
1253*4b22b933Srs200217 return mDNStrue;
1254*4b22b933Srs200217 }
1255*4b22b933Srs200217
1256*4b22b933Srs200217
StartGetPublicAddr(mDNS * m,AuthRecord * AddressRec)1257*4b22b933Srs200217 mDNSlocal void StartGetPublicAddr(mDNS *m, AuthRecord *AddressRec)
1258*4b22b933Srs200217 {
1259*4b22b933Srs200217 NATAddrRequest *req;
1260*4b22b933Srs200217 uDNS_GlobalInfo *u = &m->uDNS_info;
1261*4b22b933Srs200217
1262*4b22b933Srs200217 NATTraversalInfo *info = AllocNATInfo(m, NATOp_AddrRequest, ReceiveNATAddrResponse);
1263*4b22b933Srs200217 if (!info) { uDNS_RegisterRecord(m, AddressRec); return; }
1264*4b22b933Srs200217 AddressRec->uDNS_info.NATinfo = info;
1265*4b22b933Srs200217 info->reg.RecordRegistration = AddressRec;
1266*4b22b933Srs200217 info->state = NATState_Request;
1267*4b22b933Srs200217
1268*4b22b933Srs200217 // format message
1269*4b22b933Srs200217 req = &info->request.AddrReq;
1270*4b22b933Srs200217 req->vers = NATMAP_VERS;
1271*4b22b933Srs200217 req->opcode = NATOp_AddrRequest;
1272*4b22b933Srs200217
1273*4b22b933Srs200217 if (!u->Router.ip.v4.NotAnInteger)
1274*4b22b933Srs200217 {
1275*4b22b933Srs200217 debugf("No router. Will retry NAT traversal in %ld ticks", NATMAP_INIT_RETRY);
1276*4b22b933Srs200217 return;
1277*4b22b933Srs200217 }
1278*4b22b933Srs200217
1279*4b22b933Srs200217 SendNATMsg(info, m);
1280*4b22b933Srs200217 }
1281*4b22b933Srs200217
1282*4b22b933Srs200217
RefreshNATMapping(NATTraversalInfo * n,mDNS * m)1283*4b22b933Srs200217 mDNSlocal void RefreshNATMapping(NATTraversalInfo *n, mDNS *m)
1284*4b22b933Srs200217 {
1285*4b22b933Srs200217 n->state = NATState_Refresh;
1286*4b22b933Srs200217 n->RetryInterval = NATMAP_INIT_RETRY;
1287*4b22b933Srs200217 n->ntries = 0;
1288*4b22b933Srs200217 SendNATMsg(n, m);
1289*4b22b933Srs200217 }
1290*4b22b933Srs200217
LLQNatMapComplete(mDNS * m)1291*4b22b933Srs200217 mDNSlocal void LLQNatMapComplete(mDNS *m)
1292*4b22b933Srs200217 {
1293*4b22b933Srs200217 uDNS_GlobalInfo *u = &m->uDNS_info;
1294*4b22b933Srs200217 LLQ_Info *llqInfo;
1295*4b22b933Srs200217 NATTraversalInfo *n = u->LLQNatInfo;
1296*4b22b933Srs200217
1297*4b22b933Srs200217 if (!n) { LogMsg("Error: LLQNatMapComplete called with NULL LLQNatInfo"); return; }
1298*4b22b933Srs200217 if (n->state != NATState_Established && n->state != NATState_Legacy && n->state != NATState_Error)
1299*4b22b933Srs200217 { LogMsg("LLQNatMapComplete - bad nat state %d", n->state); return; }
1300*4b22b933Srs200217
1301*4b22b933Srs200217 u->CurrentQuery = u->ActiveQueries;
1302*4b22b933Srs200217 while (u->CurrentQuery)
1303*4b22b933Srs200217 {
1304*4b22b933Srs200217 DNSQuestion *q = u->CurrentQuery;
1305*4b22b933Srs200217 u->CurrentQuery = u->CurrentQuery->next;
1306*4b22b933Srs200217 llqInfo = q->uDNS_info.llq;
1307*4b22b933Srs200217 if (q->LongLived && llqInfo->state == LLQ_NatMapWait)
1308*4b22b933Srs200217 {
1309*4b22b933Srs200217 if (n->state == NATState_Error)
1310*4b22b933Srs200217 {
1311*4b22b933Srs200217 llqInfo->NATMap = mDNSfalse;
1312*4b22b933Srs200217 llqInfo->question->uDNS_info.responseCallback = llqResponseHndlr;
1313*4b22b933Srs200217 llqInfo->state = LLQ_Poll;
1314*4b22b933Srs200217 llqInfo->question->LastQTime = mDNSPlatformTimeNow(m) - (2 * INIT_UCAST_POLL_INTERVAL); // trigger immediate poll
1315*4b22b933Srs200217 llqInfo->question->ThisQInterval = INIT_UCAST_POLL_INTERVAL;
1316*4b22b933Srs200217 }
1317*4b22b933Srs200217 else { llqInfo->state = LLQ_GetZoneInfo; startLLQHandshake(m, llqInfo, mDNSfalse); }
1318*4b22b933Srs200217 }
1319*4b22b933Srs200217 }
1320*4b22b933Srs200217 }
1321*4b22b933Srs200217
ReceivePortMapReply(NATTraversalInfo * n,mDNS * m,mDNSu8 * pkt,mDNSu16 len)1322*4b22b933Srs200217 mDNSlocal mDNSBool ReceivePortMapReply(NATTraversalInfo *n, mDNS *m, mDNSu8 *pkt, mDNSu16 len)
1323*4b22b933Srs200217 {
1324*4b22b933Srs200217 ServiceRecordSet *srs = n->reg.ServiceRegistration;
1325*4b22b933Srs200217 mDNSIPPort priv = srs ? srs->RR_SRV.resrec.rdata->u.srv.port : m->UnicastPort4;
1326*4b22b933Srs200217 mDNSu32 lease;
1327*4b22b933Srs200217 mDNSBool deletion = !n->request.PortReq.lease.NotAnInteger;
1328*4b22b933Srs200217 NATPortMapReply *reply = (NATPortMapReply *)pkt;
1329*4b22b933Srs200217 mDNSu8 *service = srs ? srs->RR_SRV.resrec.name->c : (mDNSu8 *)"\016LLQ event port";
1330*4b22b933Srs200217
1331*4b22b933Srs200217 if (n->state != NATState_Request && n->state != NATState_Refresh)
1332*4b22b933Srs200217 { LogMsg("ReceivePortMapReply (%##s): bad state %d", service, n->state); return mDNSfalse; }
1333*4b22b933Srs200217
1334*4b22b933Srs200217 if (!pkt && !deletion) // timeout
1335*4b22b933Srs200217 {
1336*4b22b933Srs200217 #ifdef _LEGACY_NAT_TRAVERSAL_
1337*4b22b933Srs200217 mDNSIPPort pub;
1338*4b22b933Srs200217 int ntries = 0;
1339*4b22b933Srs200217 mStatus err;
1340*4b22b933Srs200217 mDNSBool tcp = (srs && DomainContainsLabelString(srs->RR_PTR.resrec.name, "_tcp"));
1341*4b22b933Srs200217
1342*4b22b933Srs200217 pub = priv; // initially request priv == pub
1343*4b22b933Srs200217 while (1)
1344*4b22b933Srs200217 {
1345*4b22b933Srs200217 err = LNT_MapPort(priv, pub, tcp);
1346*4b22b933Srs200217 if (!err)
1347*4b22b933Srs200217 {
1348*4b22b933Srs200217 n->PublicPort = pub;
1349*4b22b933Srs200217 n->state = NATState_Legacy;
1350*4b22b933Srs200217 goto end;
1351*4b22b933Srs200217 }
1352*4b22b933Srs200217 else if (err != mStatus_AlreadyRegistered || ++ntries > LEGACY_NATMAP_MAX_TRIES)
1353*4b22b933Srs200217 {
1354*4b22b933Srs200217 n->state = NATState_Error;
1355*4b22b933Srs200217 goto end;
1356*4b22b933Srs200217 }
1357*4b22b933Srs200217 else
1358*4b22b933Srs200217 {
1359*4b22b933Srs200217 // the mapping we want is taken - try a random port
1360*4b22b933Srs200217 mDNSu16 RandPort = mDNSRandom(DYN_PORT_MAX - DYN_PORT_MIN) + DYN_PORT_MIN;
1361*4b22b933Srs200217 pub = mDNSOpaque16fromIntVal(RandPort);
1362*4b22b933Srs200217 }
1363*4b22b933Srs200217 }
1364*4b22b933Srs200217 #else
1365*4b22b933Srs200217 goto end;
1366*4b22b933Srs200217 #endif // _LEGACY_NAT_TRAVERSAL_
1367*4b22b933Srs200217 }
1368*4b22b933Srs200217
1369*4b22b933Srs200217 if (len < sizeof(*reply)) { LogMsg("ReceivePortMapReply: response too short (%d bytes)", len); return mDNSfalse; }
1370*4b22b933Srs200217 if (reply->vers != NATMAP_VERS) { LogMsg("ReceivePortMapReply: received version %d (expect version %d)", pkt[0], NATMAP_VERS); return mDNSfalse; }
1371*4b22b933Srs200217 if (reply->opcode != (n->op | NATMAP_RESPONSE_MASK)) { LogMsg("ReceivePortMapReply: bad response code %d", pkt[1]); return mDNSfalse; }
1372*4b22b933Srs200217 if (reply->err.NotAnInteger) { LogMsg("ReceivePortMapReply: received error %d", mDNSVal16(reply->err)); return mDNSfalse; }
1373*4b22b933Srs200217 if (priv.NotAnInteger != reply->priv.NotAnInteger) return mDNSfalse; // packet does not match this request
1374*4b22b933Srs200217
1375*4b22b933Srs200217 if (!srs && n != m->uDNS_info.LLQNatInfo)
1376*4b22b933Srs200217 {
1377*4b22b933Srs200217 LogMsg("ReceivePortMapReply: registration cancelled"); //!!!KRS change to debugf before checkin
1378*4b22b933Srs200217 FreeNATInfo(m, n);
1379*4b22b933Srs200217 return mDNStrue;
1380*4b22b933Srs200217 }
1381*4b22b933Srs200217
1382*4b22b933Srs200217 if (deletion) { n->state = NATState_Deleted; return mDNStrue; }
1383*4b22b933Srs200217
1384*4b22b933Srs200217 lease = (mDNSu32)mDNSVal32(reply->lease);
1385*4b22b933Srs200217 if (lease > 0x70000000UL / mDNSPlatformOneSecond) lease = 0x70000000UL / mDNSPlatformOneSecond;
1386*4b22b933Srs200217
1387*4b22b933Srs200217 if (n->state == NATState_Refresh && reply->pub.NotAnInteger != n->PublicPort.NotAnInteger)
1388*4b22b933Srs200217 LogMsg("ReceivePortMapReply: NAT refresh changed public port from %d to %d", mDNSVal16(n->PublicPort), mDNSVal16(reply->pub));
1389*4b22b933Srs200217 // this should never happen
1390*4b22b933Srs200217 // !!!KRS to be defensive, use SRVChanged flag on service and deregister here
1391*4b22b933Srs200217
1392*4b22b933Srs200217 n->PublicPort = reply->pub;
1393*4b22b933Srs200217 if (reply->pub.NotAnInteger != n->request.PortReq.pub.NotAnInteger) n->request.PortReq.pub = reply->pub; // set message buffer for refreshes
1394*4b22b933Srs200217
1395*4b22b933Srs200217 n->retry = mDNSPlatformTimeNow(m) + ((mDNSs32)lease * mDNSPlatformOneSecond / 2); // retry half way to expiration
1396*4b22b933Srs200217
1397*4b22b933Srs200217 if (n->state == NATState_Refresh) { n->state = NATState_Established; return mDNStrue; }
1398*4b22b933Srs200217 n->state = NATState_Established;
1399*4b22b933Srs200217
1400*4b22b933Srs200217 end:
1401*4b22b933Srs200217 if (n->state != NATState_Established && n->state != NATState_Legacy)
1402*4b22b933Srs200217 {
1403*4b22b933Srs200217 LogMsg("NAT Port Mapping (%##s): timeout", service);
1404*4b22b933Srs200217 if (pkt) LogMsg("!!! timeout with non-null packet");
1405*4b22b933Srs200217 n->state = NATState_Error;
1406*4b22b933Srs200217 if (srs)
1407*4b22b933Srs200217 {
1408*4b22b933Srs200217 uDNS_HostnameInfo *hi = m->uDNS_info.Hostnames;
1409*4b22b933Srs200217 while (hi)
1410*4b22b933Srs200217 {
1411*4b22b933Srs200217 if (hi->arv6 && (hi->arv6->uDNS_info.state == regState_Registered || hi->arv6->uDNS_info.state == regState_Refresh)) break;
1412*4b22b933Srs200217 else hi = hi->next;
1413*4b22b933Srs200217 }
1414*4b22b933Srs200217
1415*4b22b933Srs200217 if (hi)
1416*4b22b933Srs200217 {
1417*4b22b933Srs200217 debugf("Port map failed for service %##s - using IPv6 service target", service);
1418*4b22b933Srs200217 srs->uDNS_info.NATinfo = mDNSNULL;
1419*4b22b933Srs200217 FreeNATInfo(m, n);
1420*4b22b933Srs200217 goto register_service;
1421*4b22b933Srs200217 }
1422*4b22b933Srs200217 else srs->uDNS_info.state = regState_NATError;
1423*4b22b933Srs200217 }
1424*4b22b933Srs200217 else LLQNatMapComplete(m);
1425*4b22b933Srs200217 return mDNStrue;
1426*4b22b933Srs200217 }
1427*4b22b933Srs200217 else LogOperation("Mapped private port %d to public port %d", mDNSVal16(priv), mDNSVal16(n->PublicPort));
1428*4b22b933Srs200217
1429*4b22b933Srs200217 if (!srs) { LLQNatMapComplete(m); return mDNStrue; }
1430*4b22b933Srs200217
1431*4b22b933Srs200217 register_service:
1432*4b22b933Srs200217 if (srs->uDNS_info.ns.ip.v4.NotAnInteger) SendServiceRegistration(m, srs); // non-zero server address means we already have necessary zone data to send update
1433*4b22b933Srs200217 else
1434*4b22b933Srs200217 {
1435*4b22b933Srs200217 srs->uDNS_info.state = regState_FetchingZoneData;
1436*4b22b933Srs200217 startGetZoneData(srs->RR_SRV.resrec.name, m, mDNStrue, mDNSfalse, serviceRegistrationCallback, srs);
1437*4b22b933Srs200217 }
1438*4b22b933Srs200217 return mDNStrue;
1439*4b22b933Srs200217 }
1440*4b22b933Srs200217
FormatPortMaprequest(NATTraversalInfo * info,mDNSIPPort port)1441*4b22b933Srs200217 mDNSlocal void FormatPortMaprequest(NATTraversalInfo *info, mDNSIPPort port)
1442*4b22b933Srs200217 {
1443*4b22b933Srs200217 NATPortMapRequest *req = &info->request.PortReq;
1444*4b22b933Srs200217
1445*4b22b933Srs200217 req->vers = NATMAP_VERS;
1446*4b22b933Srs200217 req->opcode = info->op;
1447*4b22b933Srs200217 req->unused.NotAnInteger = 0;
1448*4b22b933Srs200217 req->priv = port;
1449*4b22b933Srs200217 req->pub = port;
1450*4b22b933Srs200217 req->lease = mDNSOpaque32fromIntVal(NATMAP_DEFAULT_LEASE);
1451*4b22b933Srs200217 }
1452*4b22b933Srs200217
SendInitialPMapReq(mDNS * m,NATTraversalInfo * info)1453*4b22b933Srs200217 mDNSlocal void SendInitialPMapReq(mDNS *m, NATTraversalInfo *info)
1454*4b22b933Srs200217 {
1455*4b22b933Srs200217 if (!m->uDNS_info.Router.ip.v4.NotAnInteger)
1456*4b22b933Srs200217 {
1457*4b22b933Srs200217 debugf("No router. Will retry NAT traversal in %ld seconds", NATMAP_INIT_RETRY);
1458*4b22b933Srs200217 info->retry = mDNSPlatformTimeNow(m) + NATMAP_INIT_RETRY;
1459*4b22b933Srs200217 info->RetryInterval = NATMAP_INIT_RETRY;
1460*4b22b933Srs200217 return;
1461*4b22b933Srs200217 }
1462*4b22b933Srs200217 SendNATMsg(info, m);
1463*4b22b933Srs200217 return;
1464*4b22b933Srs200217 }
1465*4b22b933Srs200217
StartNATPortMap(mDNS * m,ServiceRecordSet * srs)1466*4b22b933Srs200217 mDNSlocal void StartNATPortMap(mDNS *m, ServiceRecordSet *srs)
1467*4b22b933Srs200217 {
1468*4b22b933Srs200217 NATOp_t op;
1469*4b22b933Srs200217 NATTraversalInfo *info;
1470*4b22b933Srs200217
1471*4b22b933Srs200217 if (DomainContainsLabelString(srs->RR_PTR.resrec.name, "_tcp")) op = NATOp_MapTCP;
1472*4b22b933Srs200217 else if (DomainContainsLabelString(srs->RR_PTR.resrec.name, "_udp")) op = NATOp_MapUDP;
1473*4b22b933Srs200217 else { LogMsg("StartNATPortMap: could not determine transport protocol of service %##s", srs->RR_SRV.resrec.name->c); goto error; }
1474*4b22b933Srs200217
1475*4b22b933Srs200217 if (srs->uDNS_info.NATinfo) { LogMsg("Error: StartNATPortMap - NAT info already initialized!"); FreeNATInfo(m, srs->uDNS_info.NATinfo); }
1476*4b22b933Srs200217 info = AllocNATInfo(m, op, ReceivePortMapReply);
1477*4b22b933Srs200217 srs->uDNS_info.NATinfo = info;
1478*4b22b933Srs200217 info->reg.ServiceRegistration = srs;
1479*4b22b933Srs200217 info->state = NATState_Request;
1480*4b22b933Srs200217
1481*4b22b933Srs200217 FormatPortMaprequest(info, srs->RR_SRV.resrec.rdata->u.srv.port);
1482*4b22b933Srs200217 SendInitialPMapReq(m, info);
1483*4b22b933Srs200217 return;
1484*4b22b933Srs200217
1485*4b22b933Srs200217 error:
1486*4b22b933Srs200217 startGetZoneData(srs->RR_SRV.resrec.name, m, mDNStrue, mDNSfalse, serviceRegistrationCallback, srs);
1487*4b22b933Srs200217 }
1488*4b22b933Srs200217
DeleteNATPortMapping(mDNS * m,NATTraversalInfo * nat,ServiceRecordSet * srs)1489*4b22b933Srs200217 mDNSlocal void DeleteNATPortMapping(mDNS *m, NATTraversalInfo *nat, ServiceRecordSet *srs)
1490*4b22b933Srs200217 {
1491*4b22b933Srs200217 if (nat->state == NATState_Established) // let other edge-case states expire for simplicity
1492*4b22b933Srs200217 {
1493*4b22b933Srs200217 // zero lease
1494*4b22b933Srs200217 nat->request.PortReq.lease.NotAnInteger = 0;
1495*4b22b933Srs200217 nat->state = NATState_Request;
1496*4b22b933Srs200217 SendNATMsg(nat, m);
1497*4b22b933Srs200217 }
1498*4b22b933Srs200217 #ifdef _LEGACY_NAT_TRAVERSAL_
1499*4b22b933Srs200217 else if (nat->state == NATState_Legacy)
1500*4b22b933Srs200217 {
1501*4b22b933Srs200217 mStatus err = mStatus_NoError;
1502*4b22b933Srs200217 mDNSBool tcp = srs ? DomainContainsLabelString(srs->RR_PTR.resrec.name, "_tcp") : mDNSfalse;
1503*4b22b933Srs200217 err = LNT_UnmapPort(nat->PublicPort, tcp);
1504*4b22b933Srs200217 if (err) LogMsg("Legacy NAT Traversal - unmap request failed with error %ld", err);
1505*4b22b933Srs200217 }
1506*4b22b933Srs200217 #else
1507*4b22b933Srs200217 (void)srs; // unused
1508*4b22b933Srs200217 #endif // _LEGACY_NAT_TRAVERSAL_
1509*4b22b933Srs200217 }
1510*4b22b933Srs200217
StartLLQNatMap(mDNS * m)1511*4b22b933Srs200217 mDNSlocal void StartLLQNatMap(mDNS *m)
1512*4b22b933Srs200217 {
1513*4b22b933Srs200217 NATTraversalInfo *info = AllocNATInfo(m, NATOp_MapUDP, ReceivePortMapReply);
1514*4b22b933Srs200217 uDNS_GlobalInfo *u = &m->uDNS_info;
1515*4b22b933Srs200217
1516*4b22b933Srs200217 u->LLQNatInfo = info;
1517*4b22b933Srs200217
1518*4b22b933Srs200217 info->reg.RecordRegistration = mDNSNULL;
1519*4b22b933Srs200217 info->reg.ServiceRegistration = mDNSNULL;
1520*4b22b933Srs200217 info->state = NATState_Request;
1521*4b22b933Srs200217 FormatPortMaprequest(info, m->UnicastPort4);
1522*4b22b933Srs200217 SendInitialPMapReq(m, info);
1523*4b22b933Srs200217 return;
1524*4b22b933Srs200217 }
1525*4b22b933Srs200217
1526*4b22b933Srs200217 // if LLQ NAT context unreferenced, delete the mapping
CheckForUnreferencedLLQMapping(mDNS * m)1527*4b22b933Srs200217 mDNSlocal void CheckForUnreferencedLLQMapping(mDNS *m)
1528*4b22b933Srs200217 {
1529*4b22b933Srs200217 NATTraversalInfo *nat = m->uDNS_info.LLQNatInfo;
1530*4b22b933Srs200217 DNSQuestion *q;
1531*4b22b933Srs200217
1532*4b22b933Srs200217 if (!nat) return;
1533*4b22b933Srs200217
1534*4b22b933Srs200217 for (q = m->uDNS_info.ActiveQueries; q; q = q->next)
1535*4b22b933Srs200217 if (q->LongLived && q->uDNS_info.llq->NATMap) return;
1536*4b22b933Srs200217
1537*4b22b933Srs200217 //to avoid race condition if we need to recreate before this finishes, we do one-shot deregistration
1538*4b22b933Srs200217 if (nat->state == NATState_Established || nat->state == NATState_Legacy)
1539*4b22b933Srs200217 DeleteNATPortMapping(m, nat, mDNSNULL); // for simplicity we allow other states to expire
1540*4b22b933Srs200217 FreeNATInfo(m, nat); // note: this clears the global LLQNatInfo pointer
1541*4b22b933Srs200217 }
1542*4b22b933Srs200217
1543*4b22b933Srs200217 // ***************************************************************************
1544*4b22b933Srs200217 #if COMPILER_LIKES_PRAGMA_MARK
1545*4b22b933Srs200217 #pragma mark - host name and interface management
1546*4b22b933Srs200217 #endif
1547*4b22b933Srs200217
1548*4b22b933Srs200217 // if we ever want to refine support for multiple hostnames, we can add logic matching service names to a particular hostname
1549*4b22b933Srs200217 // for now, we grab the first registered DynDNS name, if any, or a static name we learned via a reverse-map query
GetServiceTarget(uDNS_GlobalInfo * u,AuthRecord * srv,domainname * dst)1550*4b22b933Srs200217 mDNSlocal mDNSBool GetServiceTarget(uDNS_GlobalInfo *u, AuthRecord *srv, domainname *dst)
1551*4b22b933Srs200217 {
1552*4b22b933Srs200217 uDNS_HostnameInfo *hi = u->Hostnames;
1553*4b22b933Srs200217 (void)srv; // unused
1554*4b22b933Srs200217
1555*4b22b933Srs200217 dst->c[0] = 0;
1556*4b22b933Srs200217 while (hi)
1557*4b22b933Srs200217 {
1558*4b22b933Srs200217 if (hi->arv4 && (hi->arv4->uDNS_info.state == regState_Registered || hi->arv4->uDNS_info.state == regState_Refresh))
1559*4b22b933Srs200217 {
1560*4b22b933Srs200217 AssignDomainName(dst, hi->arv4->resrec.name);
1561*4b22b933Srs200217 return mDNStrue;
1562*4b22b933Srs200217 }
1563*4b22b933Srs200217 if (hi->arv6 && (hi->arv6->uDNS_info.state == regState_Registered || hi->arv6->uDNS_info.state == regState_Refresh))
1564*4b22b933Srs200217 {
1565*4b22b933Srs200217 AssignDomainName(dst, hi->arv4->resrec.name);
1566*4b22b933Srs200217 return mDNStrue;
1567*4b22b933Srs200217 }
1568*4b22b933Srs200217 hi = hi->next;
1569*4b22b933Srs200217 }
1570*4b22b933Srs200217
1571*4b22b933Srs200217 if (u->StaticHostname.c[0]) { AssignDomainName(dst, &u->StaticHostname); return mDNStrue; }
1572*4b22b933Srs200217 return mDNSfalse;
1573*4b22b933Srs200217 }
1574*4b22b933Srs200217
UpdateSRV(mDNS * m,ServiceRecordSet * srs)1575*4b22b933Srs200217 mDNSlocal void UpdateSRV(mDNS *m, ServiceRecordSet *srs)
1576*4b22b933Srs200217 {
1577*4b22b933Srs200217 uDNS_GlobalInfo *u = &m->uDNS_info;
1578*4b22b933Srs200217 ExtraResourceRecord *e;
1579*4b22b933Srs200217
1580*4b22b933Srs200217 // Target change if:
1581*4b22b933Srs200217 // We have a target and were previously waiting for one, or
1582*4b22b933Srs200217 // We had a target and no longer do, or
1583*4b22b933Srs200217 // The target has changed
1584*4b22b933Srs200217
1585*4b22b933Srs200217 domainname newtarget;
1586*4b22b933Srs200217 domainname *curtarget = &srs->RR_SRV.resrec.rdata->u.srv.target;
1587*4b22b933Srs200217 mDNSBool HaveTarget = GetServiceTarget(u, &srs->RR_SRV, &newtarget);
1588*4b22b933Srs200217 mDNSBool TargetChanged = (HaveTarget && srs->uDNS_info.state == regState_NoTarget) || (curtarget->c[0] && !HaveTarget) || !SameDomainName(curtarget, &newtarget);
1589*4b22b933Srs200217 mDNSBool HaveZoneData = srs->uDNS_info.ns.ip.v4.NotAnInteger ? mDNStrue : mDNSfalse;
1590*4b22b933Srs200217
1591*4b22b933Srs200217 // Nat state change if:
1592*4b22b933Srs200217 // We were behind a NAT, and now we are behind a new NAT, or
1593*4b22b933Srs200217 // We're not behind a NAT but our port was previously mapped to a different public port
1594*4b22b933Srs200217 // We were not behind a NAT and now we are
1595*4b22b933Srs200217
1596*4b22b933Srs200217 NATTraversalInfo *nat = srs->uDNS_info.NATinfo;
1597*4b22b933Srs200217 mDNSIPPort port = srs->RR_SRV.resrec.rdata->u.srv.port;
1598*4b22b933Srs200217 mDNSBool NATChanged = mDNSfalse;
1599*4b22b933Srs200217 mDNSBool NowBehindNAT = port.NotAnInteger && IsPrivateV4Addr(&u->AdvertisedV4);
1600*4b22b933Srs200217 mDNSBool WereBehindNAT = nat != mDNSNULL;
1601*4b22b933Srs200217 mDNSBool NATRouterChanged = nat && nat->Router.ip.v4.NotAnInteger != u->Router.ip.v4.NotAnInteger;
1602*4b22b933Srs200217 mDNSBool PortWasMapped = nat && (nat->state == NATState_Established || nat->state == NATState_Legacy) && nat->PublicPort.NotAnInteger != port.NotAnInteger;
1603*4b22b933Srs200217
1604*4b22b933Srs200217 if (WereBehindNAT && NowBehindNAT && NATRouterChanged) NATChanged = mDNStrue;
1605*4b22b933Srs200217 else if (!NowBehindNAT && PortWasMapped) NATChanged = mDNStrue;
1606*4b22b933Srs200217 else if (!WereBehindNAT && NowBehindNAT) NATChanged = mDNStrue;
1607*4b22b933Srs200217
1608*4b22b933Srs200217 if (!TargetChanged && !NATChanged) return;
1609*4b22b933Srs200217
1610*4b22b933Srs200217 debugf("UpdateSRV (%##s) HadZoneData=%d, TargetChanged=%d, HaveTarget=%d, NowBehindNAT=%d, WereBehindNAT=%d, NATRouterChanged=%d, PortWasMapped=%d",
1611*4b22b933Srs200217 srs->RR_SRV.resrec.name->c, HaveZoneData, TargetChanged, HaveTarget, NowBehindNAT, WereBehindNAT, NATRouterChanged, PortWasMapped);
1612*4b22b933Srs200217
1613*4b22b933Srs200217 switch(srs->uDNS_info.state)
1614*4b22b933Srs200217 {
1615*4b22b933Srs200217 case regState_FetchingZoneData:
1616*4b22b933Srs200217 case regState_Cancelled:
1617*4b22b933Srs200217 case regState_DeregPending:
1618*4b22b933Srs200217 case regState_DeregDeferred:
1619*4b22b933Srs200217 case regState_Unregistered:
1620*4b22b933Srs200217 case regState_NATMap:
1621*4b22b933Srs200217 case regState_ExtraQueued:
1622*4b22b933Srs200217 // In these states, the SRV has either not yet been registered (it will get up-to-date information when it is)
1623*4b22b933Srs200217 // or is in the process of, or has already been, deregistered
1624*4b22b933Srs200217 return;
1625*4b22b933Srs200217
1626*4b22b933Srs200217 case regState_Pending:
1627*4b22b933Srs200217 case regState_Refresh:
1628*4b22b933Srs200217 case regState_UpdatePending:
1629*4b22b933Srs200217 // let the in-flight operation complete before updating
1630*4b22b933Srs200217 srs->uDNS_info.SRVUpdateDeferred = mDNStrue;
1631*4b22b933Srs200217 return;
1632*4b22b933Srs200217
1633*4b22b933Srs200217 case regState_NATError:
1634*4b22b933Srs200217 if (!NATChanged) return;
1635*4b22b933Srs200217 // if nat changed, register if we have a target (below)
1636*4b22b933Srs200217
1637*4b22b933Srs200217 case regState_NoTarget:
1638*4b22b933Srs200217 if (HaveTarget)
1639*4b22b933Srs200217 {
1640*4b22b933Srs200217 debugf("UpdateSRV: %s service %##s", HaveZoneData ? (NATChanged && NowBehindNAT ? "Starting Port Map for" : "Registering") : "Getting Zone Data for", srs->RR_SRV.resrec.name->c);
1641*4b22b933Srs200217 if (!HaveZoneData)
1642*4b22b933Srs200217 {
1643*4b22b933Srs200217 srs->uDNS_info.state = regState_FetchingZoneData;
1644*4b22b933Srs200217 startGetZoneData(srs->RR_SRV.resrec.name, m, mDNStrue, mDNSfalse, serviceRegistrationCallback, srs);
1645*4b22b933Srs200217 }
1646*4b22b933Srs200217 else
1647*4b22b933Srs200217 {
1648*4b22b933Srs200217 if (nat && (NATChanged || !NowBehindNAT)) { srs->uDNS_info.NATinfo = mDNSNULL; FreeNATInfo(m, nat); }
1649*4b22b933Srs200217 if (NATChanged && NowBehindNAT) { srs->uDNS_info.state = regState_NATMap; StartNATPortMap(m, srs); }
1650*4b22b933Srs200217 else SendServiceRegistration(m, srs);
1651*4b22b933Srs200217 }
1652*4b22b933Srs200217 }
1653*4b22b933Srs200217 return;
1654*4b22b933Srs200217
1655*4b22b933Srs200217 case regState_Registered:
1656*4b22b933Srs200217 // target or nat changed. deregister service. upon completion, we'll look for a new target
1657*4b22b933Srs200217 debugf("UpdateSRV: SRV record changed for service %##s - deregistering (will re-register with new SRV)", srs->RR_SRV.resrec.name->c);
1658*4b22b933Srs200217 for (e = srs->Extras; e; e = e->next) e->r.uDNS_info.state = regState_ExtraQueued; // extra will be re-registed if the service is re-registered
1659*4b22b933Srs200217 srs->uDNS_info.SRVChanged = mDNStrue;
1660*4b22b933Srs200217 SendServiceDeregistration(m, srs);
1661*4b22b933Srs200217 return;
1662*4b22b933Srs200217 }
1663*4b22b933Srs200217 }
1664*4b22b933Srs200217
UpdateSRVRecords(mDNS * m)1665*4b22b933Srs200217 mDNSlocal void UpdateSRVRecords(mDNS *m)
1666*4b22b933Srs200217 {
1667*4b22b933Srs200217 ServiceRecordSet *srs;
1668*4b22b933Srs200217
1669*4b22b933Srs200217 for (srs = m->uDNS_info.ServiceRegistrations; srs; srs = srs->next) UpdateSRV(m, srs);
1670*4b22b933Srs200217 }
1671*4b22b933Srs200217
HostnameCallback(mDNS * const m,AuthRecord * const rr,mStatus result)1672*4b22b933Srs200217 mDNSlocal void HostnameCallback(mDNS *const m, AuthRecord *const rr, mStatus result)
1673*4b22b933Srs200217 {
1674*4b22b933Srs200217 uDNS_HostnameInfo *hi = (uDNS_HostnameInfo *)rr->RecordContext;
1675*4b22b933Srs200217
1676*4b22b933Srs200217 if (result == mStatus_MemFree)
1677*4b22b933Srs200217 {
1678*4b22b933Srs200217 if (hi)
1679*4b22b933Srs200217 {
1680*4b22b933Srs200217 if (hi->arv4 == rr) hi->arv4 = mDNSNULL;
1681*4b22b933Srs200217 else if (hi->arv4 == rr) hi->arv6 = mDNSNULL;
1682*4b22b933Srs200217 rr->RecordContext = mDNSNULL;
1683*4b22b933Srs200217 if (!hi->arv4 && !hi->arv6) ufree(hi); // free hi when both v4 and v6 AuthRecs deallocated
1684*4b22b933Srs200217 }
1685*4b22b933Srs200217 ufree(rr);
1686*4b22b933Srs200217 return;
1687*4b22b933Srs200217 }
1688*4b22b933Srs200217
1689*4b22b933Srs200217 if (result)
1690*4b22b933Srs200217 {
1691*4b22b933Srs200217 // don't unlink or free - we can retry when we get a new address/router
1692*4b22b933Srs200217 if (rr->resrec.rrtype == kDNSType_A)
1693*4b22b933Srs200217 LogMsg("HostnameCallback: Error %ld for registration of %##s IP %.4a", result, rr->resrec.name->c, &rr->resrec.rdata->u.ipv4);
1694*4b22b933Srs200217 else
1695*4b22b933Srs200217 LogMsg("HostnameCallback: Error %ld for registration of %##s IP %.16a", result, rr->resrec.name->c, &rr->resrec.rdata->u.ipv6);
1696*4b22b933Srs200217 if (!hi) { ufree(rr); return; }
1697*4b22b933Srs200217 if (rr->uDNS_info.state != regState_Unregistered) LogMsg("Error: HostnameCallback invoked with error code for record not in regState_Unregistered!");
1698*4b22b933Srs200217
1699*4b22b933Srs200217 if ((!hi->arv4 || hi->arv4->uDNS_info.state == regState_Unregistered) &&
1700*4b22b933Srs200217 (!hi->arv6 || hi->arv6->uDNS_info.state == regState_Unregistered))
1701*4b22b933Srs200217 {
1702*4b22b933Srs200217 // only deliver status if both v4 and v6 fail
1703*4b22b933Srs200217 rr->RecordContext = (void *)hi->StatusContext;
1704*4b22b933Srs200217 if (hi->StatusCallback)
1705*4b22b933Srs200217 hi->StatusCallback(m, rr, result); // client may NOT make API calls here
1706*4b22b933Srs200217 rr->RecordContext = (void *)hi;
1707*4b22b933Srs200217 }
1708*4b22b933Srs200217 return;
1709*4b22b933Srs200217 }
1710*4b22b933Srs200217 // register any pending services that require a target
1711*4b22b933Srs200217 UpdateSRVRecords(m);
1712*4b22b933Srs200217
1713*4b22b933Srs200217 // Deliver success to client
1714*4b22b933Srs200217 if (!hi) { LogMsg("HostnameCallback invoked with orphaned address record"); return; }
1715*4b22b933Srs200217 if (rr->resrec.rrtype == kDNSType_A)
1716*4b22b933Srs200217 LogMsg("Registered hostname %##s IP %.4a", rr->resrec.name->c, &rr->resrec.rdata->u.ipv4);
1717*4b22b933Srs200217 else
1718*4b22b933Srs200217 LogMsg("Registered hostname %##s IP %.16a", rr->resrec.name->c, &rr->resrec.rdata->u.ipv6);
1719*4b22b933Srs200217
1720*4b22b933Srs200217 rr->RecordContext = (void *)hi->StatusContext;
1721*4b22b933Srs200217 if (hi->StatusCallback)
1722*4b22b933Srs200217 hi->StatusCallback(m, rr, result); // client may NOT make API calls here
1723*4b22b933Srs200217 rr->RecordContext = (void *)hi;
1724*4b22b933Srs200217 }
1725*4b22b933Srs200217
1726*4b22b933Srs200217 // register record or begin NAT traversal
AdvertiseHostname(mDNS * m,uDNS_HostnameInfo * h)1727*4b22b933Srs200217 mDNSlocal void AdvertiseHostname(mDNS *m, uDNS_HostnameInfo *h)
1728*4b22b933Srs200217 {
1729*4b22b933Srs200217 uDNS_GlobalInfo *u = &m->uDNS_info;
1730*4b22b933Srs200217
1731*4b22b933Srs200217 if (u->AdvertisedV4.ip.v4.NotAnInteger && h->arv4->uDNS_info.state == regState_Unregistered)
1732*4b22b933Srs200217 {
1733*4b22b933Srs200217 if (IsPrivateV4Addr(&u->AdvertisedV4))
1734*4b22b933Srs200217 StartGetPublicAddr(m, h->arv4);
1735*4b22b933Srs200217 else
1736*4b22b933Srs200217 {
1737*4b22b933Srs200217 LogMsg("Advertising %##s IP %.4a", h->arv4->resrec.name->c, &u->AdvertisedV4.ip.v4);
1738*4b22b933Srs200217 uDNS_RegisterRecord(m, h->arv4);
1739*4b22b933Srs200217 }
1740*4b22b933Srs200217 }
1741*4b22b933Srs200217 if (u->AdvertisedV6.ip.v6.b[0] && h->arv6->uDNS_info.state == regState_Unregistered)
1742*4b22b933Srs200217 {
1743*4b22b933Srs200217 LogMsg("Advertising %##s IP %.16a", h->arv4->resrec.name->c, &u->AdvertisedV6.ip.v6);
1744*4b22b933Srs200217 uDNS_RegisterRecord(m, h->arv6);
1745*4b22b933Srs200217 }
1746*4b22b933Srs200217 }
1747*4b22b933Srs200217
FoundStaticHostname(mDNS * const m,DNSQuestion * question,const ResourceRecord * const answer,mDNSBool AddRecord)1748*4b22b933Srs200217 mDNSlocal void FoundStaticHostname(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, mDNSBool AddRecord)
1749*4b22b933Srs200217 {
1750*4b22b933Srs200217 const domainname *pktname = &answer->rdata->u.name;
1751*4b22b933Srs200217 domainname *storedname = &m->uDNS_info.StaticHostname;
1752*4b22b933Srs200217 uDNS_HostnameInfo *h = m->uDNS_info.Hostnames;
1753*4b22b933Srs200217
1754*4b22b933Srs200217 (void)question;
1755*4b22b933Srs200217
1756*4b22b933Srs200217 debugf("FoundStaticHostname: %##s -> %##s (%s)", question->qname.c, answer->rdata->u.name.c, AddRecord ? "added" : "removed");
1757*4b22b933Srs200217 if (AddRecord && !SameDomainName(pktname, storedname))
1758*4b22b933Srs200217 {
1759*4b22b933Srs200217 AssignDomainName(storedname, pktname);
1760*4b22b933Srs200217 while (h)
1761*4b22b933Srs200217 {
1762*4b22b933Srs200217 if ((h->arv4 && (h->arv4->uDNS_info.state == regState_FetchingZoneData || h->arv4->uDNS_info.state == regState_Pending || h->arv4->uDNS_info.state == regState_NATMap)) ||
1763*4b22b933Srs200217 (h->arv6 && (h->arv6->uDNS_info.state == regState_FetchingZoneData || h->arv6->uDNS_info.state == regState_Pending)))
1764*4b22b933Srs200217 {
1765*4b22b933Srs200217 // if we're in the process of registering a dynamic hostname, delay SRV update so we don't have to reregister services if the dynamic name succeeds
1766*4b22b933Srs200217 m->uDNS_info.DelaySRVUpdate = mDNStrue;
1767*4b22b933Srs200217 m->uDNS_info.NextSRVUpdate = mDNSPlatformTimeNow(m) + (5 * mDNSPlatformOneSecond);
1768*4b22b933Srs200217 return;
1769*4b22b933Srs200217 }
1770*4b22b933Srs200217 h = h->next;
1771*4b22b933Srs200217 }
1772*4b22b933Srs200217 UpdateSRVRecords(m);
1773*4b22b933Srs200217 }
1774*4b22b933Srs200217 else if (!AddRecord && SameDomainName(pktname, storedname))
1775*4b22b933Srs200217 {
1776*4b22b933Srs200217 storedname->c[0] = 0;
1777*4b22b933Srs200217 UpdateSRVRecords(m);
1778*4b22b933Srs200217 }
1779*4b22b933Srs200217 }
1780*4b22b933Srs200217
GetStaticHostname(mDNS * m)1781*4b22b933Srs200217 mDNSlocal void GetStaticHostname(mDNS *m)
1782*4b22b933Srs200217 {
1783*4b22b933Srs200217 char buf[MAX_ESCAPED_DOMAIN_NAME];
1784*4b22b933Srs200217 DNSQuestion *q = &m->uDNS_info.ReverseMap;
1785*4b22b933Srs200217 mDNSu8 *ip = m->uDNS_info.AdvertisedV4.ip.v4.b;
1786*4b22b933Srs200217 mStatus err;
1787*4b22b933Srs200217
1788*4b22b933Srs200217 if (m->uDNS_info.ReverseMapActive)
1789*4b22b933Srs200217 {
1790*4b22b933Srs200217 uDNS_StopQuery(m, q);
1791*4b22b933Srs200217 m->uDNS_info.ReverseMapActive = mDNSfalse;
1792*4b22b933Srs200217 }
1793*4b22b933Srs200217
1794*4b22b933Srs200217 m->uDNS_info.StaticHostname.c[0] = 0;
1795*4b22b933Srs200217 if (!m->uDNS_info.AdvertisedV4.ip.v4.NotAnInteger) return;
1796*4b22b933Srs200217 ubzero(q, sizeof(*q));
1797*4b22b933Srs200217 mDNS_snprintf(buf, MAX_ESCAPED_DOMAIN_NAME, "%d.%d.%d.%d.in-addr.arpa.", ip[3], ip[2], ip[1], ip[0]);
1798*4b22b933Srs200217 if (!MakeDomainNameFromDNSNameString(&q->qname, buf)) { LogMsg("Error: GetStaticHostname - bad name %s", buf); return; }
1799*4b22b933Srs200217
1800*4b22b933Srs200217 q->InterfaceID = mDNSInterface_Any;
1801*4b22b933Srs200217 q->Target = zeroAddr;
1802*4b22b933Srs200217 q->qtype = kDNSType_PTR;
1803*4b22b933Srs200217 q->qclass = kDNSClass_IN;
1804*4b22b933Srs200217 q->LongLived = mDNSfalse;
1805*4b22b933Srs200217 q->ExpectUnique = mDNSfalse;
1806*4b22b933Srs200217 q->ForceMCast = mDNSfalse;
1807*4b22b933Srs200217 q->QuestionCallback = FoundStaticHostname;
1808*4b22b933Srs200217 q->QuestionContext = mDNSNULL;
1809*4b22b933Srs200217
1810*4b22b933Srs200217 err = uDNS_StartQuery(m, q);
1811*4b22b933Srs200217 if (err) LogMsg("Error: GetStaticHostname - StartQuery returned error %d", err);
1812*4b22b933Srs200217 else m->uDNS_info.ReverseMapActive = mDNStrue;
1813*4b22b933Srs200217 }
1814*4b22b933Srs200217
AssignHostnameInfoAuthRecord(mDNS * m,uDNS_HostnameInfo * hi,int type)1815*4b22b933Srs200217 mDNSlocal void AssignHostnameInfoAuthRecord(mDNS *m, uDNS_HostnameInfo *hi, int type)
1816*4b22b933Srs200217 {
1817*4b22b933Srs200217 AuthRecord **dst = (type == mDNSAddrType_IPv4 ? &hi->arv4 : &hi->arv6);
1818*4b22b933Srs200217 AuthRecord *ar = umalloc(sizeof(*ar));
1819*4b22b933Srs200217 uDNS_GlobalInfo *u = &m->uDNS_info;
1820*4b22b933Srs200217
1821*4b22b933Srs200217 if (type != mDNSAddrType_IPv4 && type != mDNSAddrType_IPv6) { LogMsg("ERROR: AssignHostnameInfoAuthRecord - bad type %d", type); return; }
1822*4b22b933Srs200217 if (!ar) { LogMsg("ERROR: AssignHostnameInfoAuthRecord - malloc"); return; }
1823*4b22b933Srs200217
1824*4b22b933Srs200217 mDNS_SetupResourceRecord(ar, mDNSNULL, 0, type == mDNSAddrType_IPv4 ? kDNSType_A : kDNSType_AAAA, 1, kDNSRecordTypeKnownUnique, HostnameCallback, hi);
1825*4b22b933Srs200217 AssignDomainName(ar->resrec.name, &hi->fqdn);
1826*4b22b933Srs200217
1827*4b22b933Srs200217 // only set RData if we have a valid IP
1828*4b22b933Srs200217 if (type == mDNSAddrType_IPv4 && u->AdvertisedV4.ip.v4.NotAnInteger)
1829*4b22b933Srs200217 {
1830*4b22b933Srs200217 if (u->MappedV4.ip.v4.NotAnInteger) ar->resrec.rdata->u.ipv4 = u->MappedV4.ip.v4;
1831*4b22b933Srs200217 else ar->resrec.rdata->u.ipv4 = u->AdvertisedV4.ip.v4;
1832*4b22b933Srs200217 }
1833*4b22b933Srs200217 else if (type == mDNSAddrType_IPv6 && u->AdvertisedV6.ip.v6.b[0])
1834*4b22b933Srs200217 {
1835*4b22b933Srs200217 ar->resrec.rdata->u.ipv6 = u->AdvertisedV6.ip.v6;
1836*4b22b933Srs200217 }
1837*4b22b933Srs200217
1838*4b22b933Srs200217 ar->uDNS_info.state = regState_Unregistered;
1839*4b22b933Srs200217
1840*4b22b933Srs200217 if (*dst)
1841*4b22b933Srs200217 {
1842*4b22b933Srs200217 LogMsg("ERROR: AssignHostnameInfoAuthRecord - overwriting %s AuthRec", type == mDNSAddrType_IPv4 ? "IPv4" : "IPv6");
1843*4b22b933Srs200217 unlinkAR(&u->RecordRegistrations, *dst);
1844*4b22b933Srs200217 (*dst)->RecordContext = mDNSNULL; // defensively clear backpointer to avoid doubly-referenced context
1845*4b22b933Srs200217 }
1846*4b22b933Srs200217
1847*4b22b933Srs200217 *dst = ar;
1848*4b22b933Srs200217 }
1849*4b22b933Srs200217
1850*4b22b933Srs200217
1851*4b22b933Srs200217 // Deregister hostnames and register new names for each host domain with the current global
1852*4b22b933Srs200217 // values for the hostlabel and primary IP address
UpdateHostnameRegistrations(mDNS * m)1853*4b22b933Srs200217 mDNSlocal void UpdateHostnameRegistrations(mDNS *m)
1854*4b22b933Srs200217 {
1855*4b22b933Srs200217 uDNS_GlobalInfo *u = &m->uDNS_info;
1856*4b22b933Srs200217 uDNS_HostnameInfo *i;
1857*4b22b933Srs200217
1858*4b22b933Srs200217 for (i = u->Hostnames; i; i = i->next)
1859*4b22b933Srs200217 {
1860*4b22b933Srs200217 if (i->arv4 && i->arv4->uDNS_info.state != regState_Unregistered &&
1861*4b22b933Srs200217 i->arv4->resrec.rdata->u.ipv4.NotAnInteger != u->AdvertisedV4.ip.v4.NotAnInteger &&
1862*4b22b933Srs200217 i->arv4->resrec.rdata->u.ipv4.NotAnInteger !=u->MappedV4.ip.v4.NotAnInteger)
1863*4b22b933Srs200217 {
1864*4b22b933Srs200217 uDNS_DeregisterRecord(m, i->arv4);
1865*4b22b933Srs200217 i->arv4 = mDNSNULL;
1866*4b22b933Srs200217 }
1867*4b22b933Srs200217 if (i->arv6 && !mDNSPlatformMemSame(i->arv6->resrec.rdata->u.ipv6.b, u->AdvertisedV6.ip.v6.b, 16) && i->arv6->uDNS_info.state != regState_Unregistered)
1868*4b22b933Srs200217 {
1869*4b22b933Srs200217 uDNS_DeregisterRecord(m, i->arv6);
1870*4b22b933Srs200217 i->arv6 = mDNSNULL;
1871*4b22b933Srs200217 }
1872*4b22b933Srs200217
1873*4b22b933Srs200217 if (!i->arv4 && u->AdvertisedV4.ip.v4.NotAnInteger) AssignHostnameInfoAuthRecord(m, i, mDNSAddrType_IPv4);
1874*4b22b933Srs200217 else if (i->arv4 && i->arv4->uDNS_info.state == regState_Unregistered) i->arv4->resrec.rdata->u.ipv4 = u->AdvertisedV4.ip.v4; // simply overwrite unregistered
1875*4b22b933Srs200217 if (!i->arv6 && u->AdvertisedV6.ip.v6.b[0]) AssignHostnameInfoAuthRecord(m, i, mDNSAddrType_IPv6);
1876*4b22b933Srs200217 else if (i->arv6 &&i->arv6->uDNS_info.state == regState_Unregistered) i->arv6->resrec.rdata->u.ipv6 = u->AdvertisedV6.ip.v6;
1877*4b22b933Srs200217
1878*4b22b933Srs200217 AdvertiseHostname(m, i);
1879*4b22b933Srs200217 }
1880*4b22b933Srs200217 }
1881*4b22b933Srs200217
mDNS_AddDynDNSHostName(mDNS * m,const domainname * fqdn,mDNSRecordCallback * StatusCallback,const void * StatusContext)1882*4b22b933Srs200217 mDNSexport void mDNS_AddDynDNSHostName(mDNS *m, const domainname *fqdn, mDNSRecordCallback *StatusCallback, const void *StatusContext)
1883*4b22b933Srs200217 {
1884*4b22b933Srs200217 uDNS_GlobalInfo *u = &m->uDNS_info;
1885*4b22b933Srs200217 uDNS_HostnameInfo *ptr, *new;
1886*4b22b933Srs200217
1887*4b22b933Srs200217 mDNS_Lock(m);
1888*4b22b933Srs200217
1889*4b22b933Srs200217 // check if domain already registered
1890*4b22b933Srs200217 for (ptr = u->Hostnames; ptr; ptr = ptr->next)
1891*4b22b933Srs200217 {
1892*4b22b933Srs200217 if (SameDomainName(fqdn, &ptr->fqdn))
1893*4b22b933Srs200217 { LogMsg("Host Domain %##s already in list", fqdn->c); goto exit; }
1894*4b22b933Srs200217 }
1895*4b22b933Srs200217
1896*4b22b933Srs200217 // allocate and format new address record
1897*4b22b933Srs200217 new = umalloc(sizeof(*new));
1898*4b22b933Srs200217 if (!new) { LogMsg("ERROR: mDNS_AddDynDNSHostname - malloc"); goto exit; }
1899*4b22b933Srs200217 ubzero(new, sizeof(*new));
1900*4b22b933Srs200217 new->next = u->Hostnames;
1901*4b22b933Srs200217 u->Hostnames = new;
1902*4b22b933Srs200217
1903*4b22b933Srs200217 AssignDomainName(&new->fqdn, fqdn);
1904*4b22b933Srs200217 new->StatusCallback = StatusCallback;
1905*4b22b933Srs200217 new->StatusContext = StatusContext;
1906*4b22b933Srs200217
1907*4b22b933Srs200217 if (u->AdvertisedV4.ip.v4.NotAnInteger) AssignHostnameInfoAuthRecord(m, new, mDNSAddrType_IPv4);
1908*4b22b933Srs200217 else new->arv4 = mDNSNULL;
1909*4b22b933Srs200217 if (u->AdvertisedV6.ip.v6.b[0]) AssignHostnameInfoAuthRecord(m, new, mDNSAddrType_IPv6);
1910*4b22b933Srs200217 else new->arv6 = mDNSNULL;
1911*4b22b933Srs200217
1912*4b22b933Srs200217 if (u->AdvertisedV6.ip.v6.b[0] || u->AdvertisedV4.ip.v4.NotAnInteger) AdvertiseHostname(m, new);
1913*4b22b933Srs200217
1914*4b22b933Srs200217 exit:
1915*4b22b933Srs200217 mDNS_Unlock(m);
1916*4b22b933Srs200217 }
1917*4b22b933Srs200217
mDNS_RemoveDynDNSHostName(mDNS * m,const domainname * fqdn)1918*4b22b933Srs200217 mDNSexport void mDNS_RemoveDynDNSHostName(mDNS *m, const domainname *fqdn)
1919*4b22b933Srs200217 {
1920*4b22b933Srs200217 uDNS_GlobalInfo *u = &m->uDNS_info;
1921*4b22b933Srs200217 uDNS_HostnameInfo **ptr = &u->Hostnames;
1922*4b22b933Srs200217
1923*4b22b933Srs200217 mDNS_Lock(m);
1924*4b22b933Srs200217
1925*4b22b933Srs200217 while (*ptr && !SameDomainName(fqdn, &(*ptr)->fqdn)) ptr = &(*ptr)->next;
1926*4b22b933Srs200217 if (!*ptr) LogMsg("mDNS_RemoveDynDNSHostName: no such domainname %##s", fqdn->c);
1927*4b22b933Srs200217 else
1928*4b22b933Srs200217 {
1929*4b22b933Srs200217 uDNS_HostnameInfo *hi = *ptr;
1930*4b22b933Srs200217 *ptr = (*ptr)->next; // unlink
1931*4b22b933Srs200217 if (hi->arv4)
1932*4b22b933Srs200217 {
1933*4b22b933Srs200217 hi->arv4->RecordContext = mDNSNULL; // about to free wrapper struct
1934*4b22b933Srs200217 if (hi->arv4->uDNS_info.state != regState_Unregistered) uDNS_DeregisterRecord(m, hi->arv4);
1935*4b22b933Srs200217 else { ufree(hi->arv4); hi->arv4 = mDNSNULL; }
1936*4b22b933Srs200217 }
1937*4b22b933Srs200217 if (hi->arv6)
1938*4b22b933Srs200217 {
1939*4b22b933Srs200217 hi->arv6->RecordContext = mDNSNULL; // about to free wrapper struct
1940*4b22b933Srs200217 if (hi->arv6->uDNS_info.state != regState_Unregistered) uDNS_DeregisterRecord(m, hi->arv6);
1941*4b22b933Srs200217 else { ufree(hi->arv6); hi->arv6 = mDNSNULL; }
1942*4b22b933Srs200217 }
1943*4b22b933Srs200217 ufree(hi);
1944*4b22b933Srs200217 }
1945*4b22b933Srs200217 UpdateSRVRecords(m);
1946*4b22b933Srs200217 mDNS_Unlock(m);
1947*4b22b933Srs200217 }
1948*4b22b933Srs200217
mDNS_SetPrimaryInterfaceInfo(mDNS * m,const mDNSAddr * v4addr,const mDNSAddr * v6addr,const mDNSAddr * router)1949*4b22b933Srs200217 mDNSexport void mDNS_SetPrimaryInterfaceInfo(mDNS *m, const mDNSAddr *v4addr, const mDNSAddr *v6addr, const mDNSAddr *router)
1950*4b22b933Srs200217 {
1951*4b22b933Srs200217 uDNS_GlobalInfo *u = &m->uDNS_info;
1952*4b22b933Srs200217 mDNSBool v4Changed, v6Changed, RouterChanged;
1953*4b22b933Srs200217
1954*4b22b933Srs200217 if (v4addr && v4addr->type != mDNSAddrType_IPv4) { LogMsg("mDNS_SetPrimaryInterfaceInfo V4 address - incorrect type. Discarding."); return; }
1955*4b22b933Srs200217 if (v6addr && v6addr->type != mDNSAddrType_IPv6) { LogMsg("mDNS_SetPrimaryInterfaceInfo V6 address - incorrect type. Discarding."); return; }
1956*4b22b933Srs200217 if (router && router->type != mDNSAddrType_IPv4) { LogMsg("mDNS_SetPrimaryInterfaceInfo passed non-V4 router. Discarding."); return; }
1957*4b22b933Srs200217
1958*4b22b933Srs200217 mDNS_Lock(m);
1959*4b22b933Srs200217
1960*4b22b933Srs200217 v4Changed = (v4addr ? v4addr->ip.v4.NotAnInteger : 0) != u->AdvertisedV4.ip.v4.NotAnInteger;
1961*4b22b933Srs200217 v6Changed = v6addr ? !mDNSPlatformMemSame(v6addr, &u->AdvertisedV6, sizeof(*v6addr)) : (u->AdvertisedV6.ip.v6.b[0] != 0);
1962*4b22b933Srs200217 RouterChanged = (router ? router->ip.v4.NotAnInteger : 0) != u->Router.ip.v4.NotAnInteger;
1963*4b22b933Srs200217
1964*4b22b933Srs200217 #if MDNS_DEBUGMSGS
1965*4b22b933Srs200217 if (v4addr && (v4Changed || RouterChanged))
1966*4b22b933Srs200217 LogMsg("mDNS_SetPrimaryInterfaceInfo: address changed from %d.%d.%d.%d to %d.%d.%d.%d:%d",
1967*4b22b933Srs200217 u->AdvertisedV4.ip.v4.b[0], u->AdvertisedV4.ip.v4.b[1], u->AdvertisedV4.ip.v4.b[2], u->AdvertisedV4.ip.v4.b[3],
1968*4b22b933Srs200217 v4addr->ip.v4.b[0], v4addr->ip.v4.b[1], v4addr->ip.v4.b[2], v4addr->ip.v4.b[3]);
1969*4b22b933Srs200217 #endif // MDNS_DEBUGMSGS
1970*4b22b933Srs200217
1971*4b22b933Srs200217 if ((v4Changed || RouterChanged) && u->MappedV4.ip.v4.NotAnInteger) u->MappedV4.ip.v4.NotAnInteger = 0;
1972*4b22b933Srs200217 if (v4addr) u->AdvertisedV4 = *v4addr; else u->AdvertisedV4.ip.v4.NotAnInteger = 0;
1973*4b22b933Srs200217 if (v6addr) u->AdvertisedV6 = *v6addr; else ubzero(u->AdvertisedV6.ip.v6.b, 16);
1974*4b22b933Srs200217 if (router) u->Router = *router; else u->Router.ip.v4.NotAnInteger = 0;
1975*4b22b933Srs200217 // setting router to zero indicates that nat mappings must be reestablished when router is reset
1976*4b22b933Srs200217
1977*4b22b933Srs200217 if ((v4Changed || RouterChanged || v6Changed) && v4addr)
1978*4b22b933Srs200217 {
1979*4b22b933Srs200217 // don't update these unless we've got V4
1980*4b22b933Srs200217 UpdateHostnameRegistrations(m);
1981*4b22b933Srs200217 UpdateSRVRecords(m);
1982*4b22b933Srs200217 GetStaticHostname(m); // look up reverse map record to find any static hostnames for our IP address
1983*4b22b933Srs200217 }
1984*4b22b933Srs200217
1985*4b22b933Srs200217 mDNS_Unlock(m);
1986*4b22b933Srs200217 }
1987*4b22b933Srs200217
1988*4b22b933Srs200217 // ***************************************************************************
1989*4b22b933Srs200217 #if COMPILER_LIKES_PRAGMA_MARK
1990*4b22b933Srs200217 #pragma mark - Incoming Message Processing
1991*4b22b933Srs200217 #endif
1992*4b22b933Srs200217
kaListContainsAnswer(DNSQuestion * question,CacheRecord * rr)1993*4b22b933Srs200217 mDNSlocal mDNSBool kaListContainsAnswer(DNSQuestion *question, CacheRecord *rr)
1994*4b22b933Srs200217 {
1995*4b22b933Srs200217 CacheRecord *ptr;
1996*4b22b933Srs200217
1997*4b22b933Srs200217 for (ptr = question->uDNS_info.knownAnswers; ptr; ptr = ptr->next)
1998*4b22b933Srs200217 if (SameResourceRecord(&ptr->resrec, &rr->resrec)) return mDNStrue;
1999*4b22b933Srs200217
2000*4b22b933Srs200217 return mDNSfalse;
2001*4b22b933Srs200217 }
2002*4b22b933Srs200217
2003*4b22b933Srs200217
removeKnownAnswer(DNSQuestion * question,CacheRecord * rr)2004*4b22b933Srs200217 mDNSlocal void removeKnownAnswer(DNSQuestion *question, CacheRecord *rr)
2005*4b22b933Srs200217 {
2006*4b22b933Srs200217 CacheRecord *ptr, *prev = mDNSNULL;
2007*4b22b933Srs200217
2008*4b22b933Srs200217 for (ptr = question->uDNS_info.knownAnswers; ptr; ptr = ptr->next)
2009*4b22b933Srs200217 {
2010*4b22b933Srs200217 if (SameResourceRecord(&ptr->resrec, &rr->resrec))
2011*4b22b933Srs200217 {
2012*4b22b933Srs200217 if (prev) prev->next = ptr->next;
2013*4b22b933Srs200217 else question->uDNS_info.knownAnswers = ptr->next;
2014*4b22b933Srs200217 ufree(ptr);
2015*4b22b933Srs200217 return;
2016*4b22b933Srs200217 }
2017*4b22b933Srs200217 prev = ptr;
2018*4b22b933Srs200217 }
2019*4b22b933Srs200217 LogMsg("removeKnownAnswer() called for record not in KA list");
2020*4b22b933Srs200217 }
2021*4b22b933Srs200217
2022*4b22b933Srs200217
addKnownAnswer(DNSQuestion * question,const CacheRecord * rr)2023*4b22b933Srs200217 mDNSlocal void addKnownAnswer(DNSQuestion *question, const CacheRecord *rr)
2024*4b22b933Srs200217 {
2025*4b22b933Srs200217 CacheRecord *newCR = mDNSNULL;
2026*4b22b933Srs200217 mDNSu32 size;
2027*4b22b933Srs200217
2028*4b22b933Srs200217 size = sizeof(CacheRecord) + rr->resrec.rdlength - InlineCacheRDSize;
2029*4b22b933Srs200217 newCR = (CacheRecord *)umalloc(size);
2030*4b22b933Srs200217 if (!newCR) { LogMsg("ERROR: addKnownAnswer - malloc"); return; }
2031*4b22b933Srs200217 umemcpy(newCR, rr, size);
2032*4b22b933Srs200217 newCR->resrec.rdata = (RData*)&newCR->rdatastorage;
2033*4b22b933Srs200217 newCR->resrec.rdata->MaxRDLength = rr->resrec.rdlength;
2034*4b22b933Srs200217 newCR->resrec.name = &question->qname;
2035*4b22b933Srs200217 newCR->next = question->uDNS_info.knownAnswers;
2036*4b22b933Srs200217 question->uDNS_info.knownAnswers = newCR;
2037*4b22b933Srs200217 }
2038*4b22b933Srs200217
deriveGoodbyes(mDNS * const m,DNSMessage * msg,const mDNSu8 * end,DNSQuestion * question)2039*4b22b933Srs200217 mDNSlocal void deriveGoodbyes(mDNS * const m, DNSMessage *msg, const mDNSu8 *end, DNSQuestion *question)
2040*4b22b933Srs200217 {
2041*4b22b933Srs200217 const mDNSu8 *ptr;
2042*4b22b933Srs200217 int i;
2043*4b22b933Srs200217 CacheRecord *fptr, *ka, *cr, *answers = mDNSNULL, *prev = mDNSNULL;
2044*4b22b933Srs200217 LargeCacheRecord *lcr;
2045*4b22b933Srs200217
2046*4b22b933Srs200217 if (question != m->uDNS_info.CurrentQuery) { LogMsg("ERROR: deriveGoodbyes called without CurrentQuery set!"); return; }
2047*4b22b933Srs200217
2048*4b22b933Srs200217 ptr = LocateAnswers(msg, end);
2049*4b22b933Srs200217 if (!ptr) goto pkt_error;
2050*4b22b933Srs200217
2051*4b22b933Srs200217 if (!msg->h.numAnswers)
2052*4b22b933Srs200217 {
2053*4b22b933Srs200217 // delete the whole KA list
2054*4b22b933Srs200217 ka = question->uDNS_info.knownAnswers;
2055*4b22b933Srs200217 while (ka)
2056*4b22b933Srs200217 {
2057*4b22b933Srs200217 debugf("deriving goodbye for %##s", ka->resrec.name->c);
2058*4b22b933Srs200217
2059*4b22b933Srs200217 m->mDNS_reentrancy++; // Increment to allow client to legally make mDNS API calls from the callback
2060*4b22b933Srs200217 question->QuestionCallback(m, question, &ka->resrec, mDNSfalse);
2061*4b22b933Srs200217 m->mDNS_reentrancy--; // Decrement to block mDNS API calls again
2062*4b22b933Srs200217 // CAUTION: Need to be careful after calling question->QuestionCallback(),
2063*4b22b933Srs200217 // because the client's callback function is allowed to do anything,
2064*4b22b933Srs200217 // including starting/stopping queries, registering/deregistering records, etc.
2065*4b22b933Srs200217 if (question != m->uDNS_info.CurrentQuery)
2066*4b22b933Srs200217 {
2067*4b22b933Srs200217 debugf("deriveGoodbyes - question removed via callback. returning.");
2068*4b22b933Srs200217 return;
2069*4b22b933Srs200217 }
2070*4b22b933Srs200217 fptr = ka;
2071*4b22b933Srs200217 ka = ka->next;
2072*4b22b933Srs200217 ufree(fptr);
2073*4b22b933Srs200217 }
2074*4b22b933Srs200217 question->uDNS_info.knownAnswers = mDNSNULL;
2075*4b22b933Srs200217 return;
2076*4b22b933Srs200217 }
2077*4b22b933Srs200217
2078*4b22b933Srs200217 // make a list of all the new answers
2079*4b22b933Srs200217 for (i = 0; i < msg->h.numAnswers; i++)
2080*4b22b933Srs200217 {
2081*4b22b933Srs200217 lcr = (LargeCacheRecord *)umalloc(sizeof(LargeCacheRecord));
2082*4b22b933Srs200217 if (!lcr) goto malloc_error;
2083*4b22b933Srs200217 ubzero(lcr, sizeof(LargeCacheRecord));
2084*4b22b933Srs200217 ptr = GetLargeResourceRecord(m, msg, ptr, end, 0, kDNSRecordTypePacketAns, lcr);
2085*4b22b933Srs200217 if (!ptr) goto pkt_error;
2086*4b22b933Srs200217 cr = &lcr->r;
2087*4b22b933Srs200217 if (ResourceRecordAnswersQuestion(&cr->resrec, question))
2088*4b22b933Srs200217 {
2089*4b22b933Srs200217 cr->next = answers;
2090*4b22b933Srs200217 answers = cr;
2091*4b22b933Srs200217 }
2092*4b22b933Srs200217 else ufree(cr);
2093*4b22b933Srs200217 }
2094*4b22b933Srs200217
2095*4b22b933Srs200217 // make sure every known answer is in the answer list
2096*4b22b933Srs200217 ka = question->uDNS_info.knownAnswers;
2097*4b22b933Srs200217 while (ka)
2098*4b22b933Srs200217 {
2099*4b22b933Srs200217 for (cr = answers; cr; cr = cr->next)
2100*4b22b933Srs200217 { if (SameResourceRecord(&ka->resrec, &cr->resrec)) break; }
2101*4b22b933Srs200217 if (!cr)
2102*4b22b933Srs200217 {
2103*4b22b933Srs200217 // record is in KA list but not answer list - remove from KA list
2104*4b22b933Srs200217 if (prev) prev->next = ka->next;
2105*4b22b933Srs200217 else question->uDNS_info.knownAnswers = ka->next;
2106*4b22b933Srs200217 debugf("deriving goodbye for %##s", ka->resrec.name->c);
2107*4b22b933Srs200217 m->mDNS_reentrancy++; // Increment to allow client to legally make mDNS API calls from the callback
2108*4b22b933Srs200217 question->QuestionCallback(m, question, &ka->resrec, mDNSfalse);
2109*4b22b933Srs200217 m->mDNS_reentrancy--; // Decrement to block mDNS API calls again
2110*4b22b933Srs200217 // CAUTION: Need to be careful after calling question->QuestionCallback(),
2111*4b22b933Srs200217 // because the client's callback function is allowed to do anything,
2112*4b22b933Srs200217 // including starting/stopping queries, registering/deregistering records, etc.
2113*4b22b933Srs200217 if (question != m->uDNS_info.CurrentQuery)
2114*4b22b933Srs200217 {
2115*4b22b933Srs200217 debugf("deriveGoodbyes - question removed via callback. returning.");
2116*4b22b933Srs200217 return;
2117*4b22b933Srs200217 }
2118*4b22b933Srs200217 fptr = ka;
2119*4b22b933Srs200217 ka = ka->next;
2120*4b22b933Srs200217 ufree(fptr);
2121*4b22b933Srs200217 }
2122*4b22b933Srs200217 else
2123*4b22b933Srs200217 {
2124*4b22b933Srs200217 prev = ka;
2125*4b22b933Srs200217 ka = ka->next;
2126*4b22b933Srs200217 }
2127*4b22b933Srs200217 }
2128*4b22b933Srs200217
2129*4b22b933Srs200217 // free temp answers list
2130*4b22b933Srs200217 cr = answers;
2131*4b22b933Srs200217 while (cr) { fptr = cr; cr = cr->next; ufree(fptr); }
2132*4b22b933Srs200217
2133*4b22b933Srs200217 return;
2134*4b22b933Srs200217
2135*4b22b933Srs200217 pkt_error:
2136*4b22b933Srs200217 LogMsg("ERROR: deriveGoodbyes - received malformed response to query for %##s (%d)",
2137*4b22b933Srs200217 question->qname.c, question->qtype);
2138*4b22b933Srs200217 return;
2139*4b22b933Srs200217
2140*4b22b933Srs200217 malloc_error:
2141*4b22b933Srs200217 LogMsg("ERROR: Malloc");
2142*4b22b933Srs200217 }
2143*4b22b933Srs200217
pktResponseHndlr(mDNS * const m,DNSMessage * msg,const mDNSu8 * end,DNSQuestion * question,mDNSBool llq)2144*4b22b933Srs200217 mDNSlocal void pktResponseHndlr(mDNS * const m, DNSMessage *msg, const mDNSu8 *end, DNSQuestion *question, mDNSBool llq)
2145*4b22b933Srs200217 {
2146*4b22b933Srs200217 const mDNSu8 *ptr;
2147*4b22b933Srs200217 int i;
2148*4b22b933Srs200217 CacheRecord *cr = &m->rec.r;
2149*4b22b933Srs200217 mDNSBool goodbye, inKAList;
2150*4b22b933Srs200217 int followedCNames = 0;
2151*4b22b933Srs200217 static const int maxCNames = 5;
2152*4b22b933Srs200217 LLQ_Info *llqInfo = question->uDNS_info.llq;
2153*4b22b933Srs200217 domainname origname;
2154*4b22b933Srs200217 origname.c[0] = 0;
2155*4b22b933Srs200217
2156*4b22b933Srs200217 if (question != m->uDNS_info.CurrentQuery)
2157*4b22b933Srs200217 { LogMsg("ERROR: pktResponseHdnlr called without CurrentQuery ptr set!"); return; }
2158*4b22b933Srs200217
2159*4b22b933Srs200217 if (question->uDNS_info.Answered == 0 && msg->h.numAnswers == 0 && !llq)
2160*4b22b933Srs200217 {
2161*4b22b933Srs200217 /* NXDOMAIN error or empty RR set - notify client */
2162*4b22b933Srs200217 question->uDNS_info.Answered = mDNStrue;
2163*4b22b933Srs200217
2164*4b22b933Srs200217 /* Create empty resource record */
2165*4b22b933Srs200217 cr->resrec.RecordType = kDNSRecordTypeUnregistered;
2166*4b22b933Srs200217 cr->resrec.InterfaceID = mDNSNULL;
2167*4b22b933Srs200217 cr->resrec.name = &question->qname;
2168*4b22b933Srs200217 cr->resrec.rrtype = question->qtype;
2169*4b22b933Srs200217 cr->resrec.rrclass = question->qclass;
2170*4b22b933Srs200217 cr->resrec.rroriginalttl = 1; /* What should we use for the TTL? TTL from SOA for domain? */
2171*4b22b933Srs200217 cr->resrec.rdlength = 0;
2172*4b22b933Srs200217 cr->resrec.rdestimate = 0;
2173*4b22b933Srs200217 cr->resrec.namehash = 0;
2174*4b22b933Srs200217 cr->resrec.namehash = 0;
2175*4b22b933Srs200217 cr->resrec.rdata = (RData*)&cr->rdatastorage;
2176*4b22b933Srs200217 cr->resrec.rdata->MaxRDLength = cr->resrec.rdlength;
2177*4b22b933Srs200217
2178*4b22b933Srs200217 /* Pass empty answer to callback */
2179*4b22b933Srs200217 m->mDNS_reentrancy++; // Increment to allow client to legally make mDNS API calls from the callback
2180*4b22b933Srs200217 question->QuestionCallback(m, question, &cr->resrec, 0);
2181*4b22b933Srs200217 m->mDNS_reentrancy--; // Decrement to block mDNS API calls again
2182*4b22b933Srs200217 // CAUTION: Need to be careful after calling question->QuestionCallback(),
2183*4b22b933Srs200217 // because the client's callback function is allowed to do anything,
2184*4b22b933Srs200217 // including starting/stopping queries, registering/deregistering records, etc.
2185*4b22b933Srs200217 m->rec.r.resrec.RecordType = 0; // Clear RecordType to show we're not still using it
2186*4b22b933Srs200217 if (question != m->uDNS_info.CurrentQuery)
2187*4b22b933Srs200217 {
2188*4b22b933Srs200217 debugf("pktResponseHndlr - CurrentQuery changed by QuestionCallback - returning.");
2189*4b22b933Srs200217 return;
2190*4b22b933Srs200217 }
2191*4b22b933Srs200217 }
2192*4b22b933Srs200217
2193*4b22b933Srs200217 question->uDNS_info.Answered = mDNStrue;
2194*4b22b933Srs200217
2195*4b22b933Srs200217 ptr = LocateAnswers(msg, end);
2196*4b22b933Srs200217 if (!ptr) goto pkt_error;
2197*4b22b933Srs200217
2198*4b22b933Srs200217 for (i = 0; i < msg->h.numAnswers; i++)
2199*4b22b933Srs200217 {
2200*4b22b933Srs200217 ptr = GetLargeResourceRecord(m, msg, ptr, end, 0, kDNSRecordTypePacketAns, &m->rec);
2201*4b22b933Srs200217 if (!ptr) goto pkt_error;
2202*4b22b933Srs200217 if (ResourceRecordAnswersQuestion(&cr->resrec, question))
2203*4b22b933Srs200217 {
2204*4b22b933Srs200217 goodbye = llq ? ((mDNSs32)cr->resrec.rroriginalttl == -1) : mDNSfalse;
2205*4b22b933Srs200217 if (cr->resrec.rrtype == kDNSType_CNAME)
2206*4b22b933Srs200217 {
2207*4b22b933Srs200217 if (followedCNames > (maxCNames - 1)) LogMsg("Error: too many CNAME referals for question %##s", &origname);
2208*4b22b933Srs200217 else
2209*4b22b933Srs200217 {
2210*4b22b933Srs200217 debugf("Following cname %##s -> %##s", question->qname.c, cr->resrec.rdata->u.name.c);
2211*4b22b933Srs200217 if (question->ReturnCNAME)
2212*4b22b933Srs200217 {
2213*4b22b933Srs200217 m->mDNS_reentrancy++; // Increment to allow client to legally make mDNS API calls from the callback
2214*4b22b933Srs200217 question->QuestionCallback(m, question, &cr->resrec, !goodbye);
2215*4b22b933Srs200217 m->mDNS_reentrancy--; // Decrement to block mDNS API calls again
2216*4b22b933Srs200217 // CAUTION: Need to be careful after calling question->QuestionCallback(),
2217*4b22b933Srs200217 // because the client's callback function is allowed to do anything,
2218*4b22b933Srs200217 // including starting/stopping queries, registering/deregistering records, etc.
2219*4b22b933Srs200217 if (question != m->uDNS_info.CurrentQuery)
2220*4b22b933Srs200217 {
2221*4b22b933Srs200217 m->rec.r.resrec.RecordType = 0; // Clear RecordType to show we're not still using it
2222*4b22b933Srs200217 debugf("pktResponseHndlr - CurrentQuery changed by QuestionCallback - returning.");
2223*4b22b933Srs200217 return;
2224*4b22b933Srs200217 }
2225*4b22b933Srs200217 }
2226*4b22b933Srs200217 AssignDomainName(&origname, &question->qname);
2227*4b22b933Srs200217 AssignDomainName(&question->qname, &cr->resrec.rdata->u.name);
2228*4b22b933Srs200217 question->qnamehash = DomainNameHashValue(&question->qname);
2229*4b22b933Srs200217 followedCNames++;
2230*4b22b933Srs200217 i = -1; // restart packet answer matching
2231*4b22b933Srs200217 ptr = LocateAnswers(msg, end);
2232*4b22b933Srs200217 m->rec.r.resrec.RecordType = 0; // Clear RecordType to show we're not still using it
2233*4b22b933Srs200217 continue;
2234*4b22b933Srs200217 }
2235*4b22b933Srs200217 }
2236*4b22b933Srs200217
2237*4b22b933Srs200217 inKAList = kaListContainsAnswer(question, cr);
2238*4b22b933Srs200217
2239*4b22b933Srs200217 if ((goodbye && !inKAList) || (!goodbye && inKAList))
2240*4b22b933Srs200217 {
2241*4b22b933Srs200217 m->rec.r.resrec.RecordType = 0; // Clear RecordType to show we're not still using it
2242*4b22b933Srs200217 continue; // list up to date
2243*4b22b933Srs200217 }
2244*4b22b933Srs200217 if (!inKAList) addKnownAnswer(question, cr);
2245*4b22b933Srs200217 if (goodbye) removeKnownAnswer(question, cr);
2246*4b22b933Srs200217 m->mDNS_reentrancy++; // Increment to allow client to legally make mDNS API calls from the callback
2247*4b22b933Srs200217 question->QuestionCallback(m, question, &cr->resrec, !goodbye);
2248*4b22b933Srs200217 m->mDNS_reentrancy--; // Decrement to block mDNS API calls again
2249*4b22b933Srs200217 if (question != m->uDNS_info.CurrentQuery)
2250*4b22b933Srs200217 {
2251*4b22b933Srs200217 m->rec.r.resrec.RecordType = 0; // Clear RecordType to show we're not still using it
2252*4b22b933Srs200217 debugf("pktResponseHndlr - CurrentQuery changed by QuestionCallback - returning");
2253*4b22b933Srs200217 return;
2254*4b22b933Srs200217 }
2255*4b22b933Srs200217 }
2256*4b22b933Srs200217
2257*4b22b933Srs200217 m->rec.r.resrec.RecordType = 0; // Clear RecordType to show we're not still using it
2258*4b22b933Srs200217 }
2259*4b22b933Srs200217
2260*4b22b933Srs200217 if (!llq || llqInfo->state == LLQ_Poll || llqInfo->deriveRemovesOnResume)
2261*4b22b933Srs200217 {
2262*4b22b933Srs200217 deriveGoodbyes(m, msg, end,question);
2263*4b22b933Srs200217 if (llq && llqInfo->deriveRemovesOnResume) llqInfo->deriveRemovesOnResume = mDNSfalse;
2264*4b22b933Srs200217 }
2265*4b22b933Srs200217
2266*4b22b933Srs200217 // Our interval may be set lower to recover from failures -- now that we have an answer, fully back off retry.
2267*4b22b933Srs200217 // If the server advertised an LLQ-specific port number then that implies that this zone
2268*4b22b933Srs200217 // *wants* to support LLQs, so if the setup fails (e.g. because we are behind a NAT)
2269*4b22b933Srs200217 // then we use a slightly faster polling rate to give slightly better user experience.
2270*4b22b933Srs200217 if (llq && llqInfo->state == LLQ_Poll && llqInfo->servPort.NotAnInteger) question->ThisQInterval = LLQ_POLL_INTERVAL;
2271*4b22b933Srs200217 else if (question->ThisQInterval < MAX_UCAST_POLL_INTERVAL) question->ThisQInterval = MAX_UCAST_POLL_INTERVAL;
2272*4b22b933Srs200217 return;
2273*4b22b933Srs200217
2274*4b22b933Srs200217 pkt_error:
2275*4b22b933Srs200217 LogMsg("ERROR: pktResponseHndlr - received malformed response to query for %##s (%d)",
2276*4b22b933Srs200217 question->qname.c, question->qtype);
2277*4b22b933Srs200217 return;
2278*4b22b933Srs200217 }
2279*4b22b933Srs200217
simpleResponseHndlr(mDNS * const m,DNSMessage * msg,const mDNSu8 * end,DNSQuestion * question,void * context)2280*4b22b933Srs200217 mDNSlocal void simpleResponseHndlr(mDNS * const m, DNSMessage *msg, const mDNSu8 *end, DNSQuestion *question, void *context)
2281*4b22b933Srs200217 {
2282*4b22b933Srs200217 (void)context; // unused
2283*4b22b933Srs200217 pktResponseHndlr(m, msg, end, question, mDNSfalse);
2284*4b22b933Srs200217 }
2285*4b22b933Srs200217
llqResponseHndlr(mDNS * const m,DNSMessage * msg,const mDNSu8 * end,DNSQuestion * question,void * context)2286*4b22b933Srs200217 mDNSlocal void llqResponseHndlr(mDNS * const m, DNSMessage *msg, const mDNSu8 *end, DNSQuestion *question, void *context)
2287*4b22b933Srs200217 {
2288*4b22b933Srs200217 (void)context; // unused
2289*4b22b933Srs200217 pktResponseHndlr(m, msg, end, question, mDNStrue);
2290*4b22b933Srs200217 }
2291*4b22b933Srs200217
ParseTSIGError(mDNS * m,const DNSMessage * msg,const mDNSu8 * end,const domainname * displayname)2292*4b22b933Srs200217 mDNSlocal mStatus ParseTSIGError(mDNS *m, const DNSMessage *msg, const mDNSu8 *end, const domainname *displayname)
2293*4b22b933Srs200217 {
2294*4b22b933Srs200217 LargeCacheRecord lcr;
2295*4b22b933Srs200217 const mDNSu8 *ptr;
2296*4b22b933Srs200217 mStatus err = mStatus_NoError;
2297*4b22b933Srs200217 int i;
2298*4b22b933Srs200217
2299*4b22b933Srs200217 ptr = LocateAdditionals(msg, end);
2300*4b22b933Srs200217 if (!ptr) goto finish;
2301*4b22b933Srs200217
2302*4b22b933Srs200217 for (i = 0; i < msg->h.numAdditionals; i++)
2303*4b22b933Srs200217 {
2304*4b22b933Srs200217 ptr = GetLargeResourceRecord(m, msg, ptr, end, 0, kDNSRecordTypePacketAdd, &lcr);
2305*4b22b933Srs200217 if (!ptr) goto finish;
2306*4b22b933Srs200217 if (lcr.r.resrec.rrtype == kDNSType_TSIG)
2307*4b22b933Srs200217 {
2308*4b22b933Srs200217 mDNSu32 macsize;
2309*4b22b933Srs200217 mDNSu8 *rd = lcr.r.resrec.rdata->u.data;
2310*4b22b933Srs200217 mDNSu8 *rdend = rd + MaximumRDSize;
2311*4b22b933Srs200217 int alglen = DomainNameLength(&lcr.r.resrec.rdata->u.name);
2312*4b22b933Srs200217
2313*4b22b933Srs200217 if (rd + alglen > rdend) goto finish;
2314*4b22b933Srs200217 rd += alglen; // algorithm name
2315*4b22b933Srs200217 if (rd + 6 > rdend) goto finish;
2316*4b22b933Srs200217 rd += 6; // 48-bit timestamp
2317*4b22b933Srs200217 if (rd + sizeof(mDNSOpaque16) > rdend) goto finish;
2318*4b22b933Srs200217 rd += sizeof(mDNSOpaque16); // fudge
2319*4b22b933Srs200217 if (rd + sizeof(mDNSOpaque16) > rdend) goto finish;
2320*4b22b933Srs200217 macsize = mDNSVal16(*(mDNSOpaque16 *)rd);
2321*4b22b933Srs200217 rd += sizeof(mDNSOpaque16); // MAC size
2322*4b22b933Srs200217 if (rd + macsize > rdend) goto finish;
2323*4b22b933Srs200217 rd += macsize;
2324*4b22b933Srs200217 if (rd + sizeof(mDNSOpaque16) > rdend) goto finish;
2325*4b22b933Srs200217 rd += sizeof(mDNSOpaque16); // orig id
2326*4b22b933Srs200217 if (rd + sizeof(mDNSOpaque16) > rdend) goto finish;
2327*4b22b933Srs200217 err = mDNSVal16(*(mDNSOpaque16 *)rd); // error code
2328*4b22b933Srs200217
2329*4b22b933Srs200217 if (err == TSIG_ErrBadSig) { LogMsg("%##s: bad signature", displayname->c); err = mStatus_BadSig; }
2330*4b22b933Srs200217 else if (err == TSIG_ErrBadKey) { LogMsg("%##s: bad key", displayname->c); err = mStatus_BadKey; }
2331*4b22b933Srs200217 else if (err == TSIG_ErrBadTime) { LogMsg("%##s: bad time", displayname->c); err = mStatus_BadTime; }
2332*4b22b933Srs200217 else if (err) { LogMsg("%##s: unknown tsig error %d", displayname->c, err); err = mStatus_UnknownErr; }
2333*4b22b933Srs200217 goto finish;
2334*4b22b933Srs200217 }
2335*4b22b933Srs200217 }
2336*4b22b933Srs200217
2337*4b22b933Srs200217 finish:
2338*4b22b933Srs200217 return err;
2339*4b22b933Srs200217 }
2340*4b22b933Srs200217
checkUpdateResult(domainname * displayname,mDNSu8 rcode,mDNS * m,const DNSMessage * msg,const mDNSu8 * end)2341*4b22b933Srs200217 mDNSlocal mStatus checkUpdateResult(domainname *displayname, mDNSu8 rcode, mDNS *m, const DNSMessage *msg, const mDNSu8 *end)
2342*4b22b933Srs200217 {
2343*4b22b933Srs200217 (void)msg; // currently unused, needed for TSIG errors
2344*4b22b933Srs200217 if (!rcode) return mStatus_NoError;
2345*4b22b933Srs200217 else if (rcode == kDNSFlag1_RC_YXDomain)
2346*4b22b933Srs200217 {
2347*4b22b933Srs200217 debugf("name in use: %##s", displayname->c);
2348*4b22b933Srs200217 return mStatus_NameConflict;
2349*4b22b933Srs200217 }
2350*4b22b933Srs200217 else if (rcode == kDNSFlag1_RC_Refused)
2351*4b22b933Srs200217 {
2352*4b22b933Srs200217 LogMsg("Update %##s refused", displayname->c);
2353*4b22b933Srs200217 return mStatus_Refused;
2354*4b22b933Srs200217 }
2355*4b22b933Srs200217 else if (rcode == kDNSFlag1_RC_NXRRSet)
2356*4b22b933Srs200217 {
2357*4b22b933Srs200217 LogMsg("Reregister refused (NXRRSET): %##s", displayname->c);
2358*4b22b933Srs200217 return mStatus_NoSuchRecord;
2359*4b22b933Srs200217 }
2360*4b22b933Srs200217 else if (rcode == kDNSFlag1_RC_NotAuth)
2361*4b22b933Srs200217 {
2362*4b22b933Srs200217 // TSIG errors should come with FmtErr as per RFC 2845, but BIND 9 sends them with NotAuth so we look here too
2363*4b22b933Srs200217 mStatus tsigerr = ParseTSIGError(m, msg, end, displayname);
2364*4b22b933Srs200217 if (!tsigerr)
2365*4b22b933Srs200217 {
2366*4b22b933Srs200217 LogMsg("Permission denied (NOAUTH): %##s", displayname->c);
2367*4b22b933Srs200217 return mStatus_UnknownErr;
2368*4b22b933Srs200217 }
2369*4b22b933Srs200217 else return tsigerr;
2370*4b22b933Srs200217 }
2371*4b22b933Srs200217 else if (rcode == kDNSFlag1_RC_FmtErr)
2372*4b22b933Srs200217 {
2373*4b22b933Srs200217 mStatus tsigerr = ParseTSIGError(m, msg, end, displayname);
2374*4b22b933Srs200217 if (!tsigerr)
2375*4b22b933Srs200217 {
2376*4b22b933Srs200217 LogMsg("Format Error: %##s", displayname->c);
2377*4b22b933Srs200217 return mStatus_UnknownErr;
2378*4b22b933Srs200217 }
2379*4b22b933Srs200217 else return tsigerr;
2380*4b22b933Srs200217 }
2381*4b22b933Srs200217 else
2382*4b22b933Srs200217 {
2383*4b22b933Srs200217 LogMsg("Update %##s failed with rcode %d", displayname->c, rcode);
2384*4b22b933Srs200217 return mStatus_UnknownErr;
2385*4b22b933Srs200217 }
2386*4b22b933Srs200217 }
2387*4b22b933Srs200217
hndlServiceUpdateReply(mDNS * const m,ServiceRecordSet * srs,mStatus err)2388*4b22b933Srs200217 mDNSlocal void hndlServiceUpdateReply(mDNS * const m, ServiceRecordSet *srs, mStatus err)
2389*4b22b933Srs200217 {
2390*4b22b933Srs200217 mDNSBool InvokeCallback = mDNSfalse;
2391*4b22b933Srs200217 uDNS_RegInfo *info = &srs->uDNS_info;
2392*4b22b933Srs200217 NATTraversalInfo *nat = srs->uDNS_info.NATinfo;
2393*4b22b933Srs200217 ExtraResourceRecord **e = &srs->Extras;
2394*4b22b933Srs200217 AuthRecord *txt = &srs->RR_TXT;
2395*4b22b933Srs200217 uDNS_RegInfo *txtInfo = &txt->uDNS_info;
2396*4b22b933Srs200217 switch (info->state)
2397*4b22b933Srs200217 {
2398*4b22b933Srs200217 case regState_Pending:
2399*4b22b933Srs200217 if (err == mStatus_NameConflict && !info->TestForSelfConflict)
2400*4b22b933Srs200217 {
2401*4b22b933Srs200217 info->TestForSelfConflict = mDNStrue;
2402*4b22b933Srs200217 debugf("checking for self-conflict of service %##s", srs->RR_SRV.resrec.name->c);
2403*4b22b933Srs200217 SendServiceRegistration(m, srs);
2404*4b22b933Srs200217 return;
2405*4b22b933Srs200217 }
2406*4b22b933Srs200217 else if (info->TestForSelfConflict)
2407*4b22b933Srs200217 {
2408*4b22b933Srs200217 info->TestForSelfConflict = mDNSfalse;
2409*4b22b933Srs200217 if (err == mStatus_NoSuchRecord) err = mStatus_NameConflict; // NoSuchRecord implies that our prereq was not met, so we actually have a name conflict
2410*4b22b933Srs200217 if (err) info->state = regState_Unregistered;
2411*4b22b933Srs200217 else info->state = regState_Registered;
2412*4b22b933Srs200217 InvokeCallback = mDNStrue;
2413*4b22b933Srs200217 break;
2414*4b22b933Srs200217 }
2415*4b22b933Srs200217 else if (err == mStatus_UnknownErr && info->lease)
2416*4b22b933Srs200217 {
2417*4b22b933Srs200217 LogMsg("Re-trying update of service %##s without lease option", srs->RR_SRV.resrec.name->c);
2418*4b22b933Srs200217 info->lease = mDNSfalse;
2419*4b22b933Srs200217 SendServiceRegistration(m, srs);
2420*4b22b933Srs200217 return;
2421*4b22b933Srs200217 }
2422*4b22b933Srs200217 else
2423*4b22b933Srs200217 {
2424*4b22b933Srs200217 if (err) { LogMsg("Error %ld for registration of service %##s", err, srs->RR_SRV.resrec.name->c); info->state = regState_Unregistered; } //!!!KRS make sure all structs will still get cleaned up when client calls DeregisterService with this state
2425*4b22b933Srs200217 else info->state = regState_Registered;
2426*4b22b933Srs200217 InvokeCallback = mDNStrue;
2427*4b22b933Srs200217 break;
2428*4b22b933Srs200217 }
2429*4b22b933Srs200217 case regState_Refresh:
2430*4b22b933Srs200217 if (err)
2431*4b22b933Srs200217 {
2432*4b22b933Srs200217 LogMsg("Error %ld for refresh of service %##s", err, srs->RR_SRV.resrec.name->c);
2433*4b22b933Srs200217 InvokeCallback = mDNStrue;
2434*4b22b933Srs200217 info->state = regState_Unregistered;
2435*4b22b933Srs200217 }
2436*4b22b933Srs200217 else info->state = regState_Registered;
2437*4b22b933Srs200217 break;
2438*4b22b933Srs200217 case regState_DeregPending:
2439*4b22b933Srs200217 if (err) LogMsg("Error %ld for deregistration of service %##s", err, srs->RR_SRV.resrec.name->c);
2440*4b22b933Srs200217 if (info->SRVChanged)
2441*4b22b933Srs200217 {
2442*4b22b933Srs200217 info->state = regState_NoTarget; // NoTarget will allow us to pick up new target OR nat traversal state
2443*4b22b933Srs200217 break;
2444*4b22b933Srs200217 }
2445*4b22b933Srs200217 err = mStatus_MemFree;
2446*4b22b933Srs200217 InvokeCallback = mDNStrue;
2447*4b22b933Srs200217 if (nat)
2448*4b22b933Srs200217 {
2449*4b22b933Srs200217 if (nat->state == NATState_Deleted) { info->NATinfo = mDNSNULL; FreeNATInfo(m, nat); } // deletion copmleted
2450*4b22b933Srs200217 else nat->reg.ServiceRegistration = mDNSNULL; // allow mapping deletion to continue
2451*4b22b933Srs200217 }
2452*4b22b933Srs200217 info->state = regState_Unregistered;
2453*4b22b933Srs200217 break;
2454*4b22b933Srs200217 case regState_DeregDeferred:
2455*4b22b933Srs200217 if (err)
2456*4b22b933Srs200217 {
2457*4b22b933Srs200217 debugf("Error %ld received prior to deferred derigstration of %##s", err, srs->RR_SRV.resrec.name->c);
2458*4b22b933Srs200217 err = mStatus_MemFree;
2459*4b22b933Srs200217 InvokeCallback = mDNStrue;
2460*4b22b933Srs200217 info->state = regState_Unregistered;
2461*4b22b933Srs200217 break;
2462*4b22b933Srs200217 }
2463*4b22b933Srs200217 else
2464*4b22b933Srs200217 {
2465*4b22b933Srs200217 debugf("Performing deferred deregistration of %##s", srs->RR_SRV.resrec.name->c);
2466*4b22b933Srs200217 info->state = regState_Registered;
2467*4b22b933Srs200217 SendServiceDeregistration(m, srs);
2468*4b22b933Srs200217 return;
2469*4b22b933Srs200217 }
2470*4b22b933Srs200217 case regState_UpdatePending:
2471*4b22b933Srs200217 if (err)
2472*4b22b933Srs200217 {
2473*4b22b933Srs200217 LogMsg("hndlServiceUpdateReply: error updating TXT record for service %##s", srs->RR_SRV.resrec.name->c);
2474*4b22b933Srs200217 info->state = regState_Unregistered;
2475*4b22b933Srs200217 InvokeCallback = mDNStrue;
2476*4b22b933Srs200217 }
2477*4b22b933Srs200217 else
2478*4b22b933Srs200217 {
2479*4b22b933Srs200217 info->state = regState_Registered;
2480*4b22b933Srs200217 // deallocate old RData
2481*4b22b933Srs200217 if (txtInfo->UpdateRDCallback) txtInfo->UpdateRDCallback(m, txt, txtInfo->OrigRData);
2482*4b22b933Srs200217 SetNewRData(&txt->resrec, txtInfo->InFlightRData, txtInfo->InFlightRDLen);
2483*4b22b933Srs200217 txtInfo->OrigRData = mDNSNULL;
2484*4b22b933Srs200217 txtInfo->InFlightRData = mDNSNULL;
2485*4b22b933Srs200217 }
2486*4b22b933Srs200217 break;
2487*4b22b933Srs200217 case regState_FetchingZoneData:
2488*4b22b933Srs200217 case regState_Registered:
2489*4b22b933Srs200217 case regState_Cancelled:
2490*4b22b933Srs200217 case regState_Unregistered:
2491*4b22b933Srs200217 case regState_NATMap:
2492*4b22b933Srs200217 case regState_NoTarget:
2493*4b22b933Srs200217 case regState_ExtraQueued:
2494*4b22b933Srs200217 case regState_NATError:
2495*4b22b933Srs200217 LogMsg("hndlServiceUpdateReply called for service %##s in unexpected state %d with error %ld. Unlinking.",
2496*4b22b933Srs200217 srs->RR_SRV.resrec.name->c, info->state, err);
2497*4b22b933Srs200217 err = mStatus_UnknownErr;
2498*4b22b933Srs200217 }
2499*4b22b933Srs200217
2500*4b22b933Srs200217 if ((info->SRVChanged || info->SRVUpdateDeferred) && (info->state == regState_NoTarget || info->state == regState_Registered))
2501*4b22b933Srs200217 {
2502*4b22b933Srs200217 if (InvokeCallback)
2503*4b22b933Srs200217 {
2504*4b22b933Srs200217 info->ClientCallbackDeferred = mDNStrue;
2505*4b22b933Srs200217 info->DeferredStatus = err;
2506*4b22b933Srs200217 }
2507*4b22b933Srs200217 info->SRVChanged = mDNSfalse;
2508*4b22b933Srs200217 UpdateSRV(m, srs);
2509*4b22b933Srs200217 return;
2510*4b22b933Srs200217 }
2511*4b22b933Srs200217
2512*4b22b933Srs200217 while (*e)
2513*4b22b933Srs200217 {
2514*4b22b933Srs200217 uDNS_RegInfo *einfo = &(*e)->r.uDNS_info;
2515*4b22b933Srs200217 if (einfo->state == regState_ExtraQueued)
2516*4b22b933Srs200217 {
2517*4b22b933Srs200217 if (info->state == regState_Registered && !err)
2518*4b22b933Srs200217 {
2519*4b22b933Srs200217 // extra resource record queued for this service - copy zone info and register
2520*4b22b933Srs200217 AssignDomainName(&einfo->zone, &info->zone);
2521*4b22b933Srs200217 einfo->ns = info->ns;
2522*4b22b933Srs200217 einfo->port = info->port;
2523*4b22b933Srs200217 einfo->lease = info->lease;
2524*4b22b933Srs200217 sendRecordRegistration(m, &(*e)->r);
2525*4b22b933Srs200217 e = &(*e)->next;
2526*4b22b933Srs200217 }
2527*4b22b933Srs200217 else if (err && einfo->state != regState_Unregistered)
2528*4b22b933Srs200217 {
2529*4b22b933Srs200217 // unlink extra from list
2530*4b22b933Srs200217 einfo->state = regState_Unregistered;
2531*4b22b933Srs200217 *e = (*e)->next;
2532*4b22b933Srs200217 }
2533*4b22b933Srs200217 else e = &(*e)->next;
2534*4b22b933Srs200217 }
2535*4b22b933Srs200217 else e = &(*e)->next;
2536*4b22b933Srs200217 }
2537*4b22b933Srs200217
2538*4b22b933Srs200217 srs->RR_SRV.ThisAPInterval = INIT_UCAST_POLL_INTERVAL - 1; // reset retry delay for future refreshes, dereg, etc.
2539*4b22b933Srs200217 if (info->state == regState_Unregistered) unlinkSRS(m, srs);
2540*4b22b933Srs200217 else if (txtInfo->QueuedRData && info->state == regState_Registered)
2541*4b22b933Srs200217 {
2542*4b22b933Srs200217 if (InvokeCallback)
2543*4b22b933Srs200217 {
2544*4b22b933Srs200217 // if we were supposed to give a client callback, we'll do it after we update the primary txt record
2545*4b22b933Srs200217 info->ClientCallbackDeferred = mDNStrue;
2546*4b22b933Srs200217 info->DeferredStatus = err;
2547*4b22b933Srs200217 }
2548*4b22b933Srs200217 info->state = regState_UpdatePending;
2549*4b22b933Srs200217 txtInfo->InFlightRData = txtInfo->QueuedRData;
2550*4b22b933Srs200217 txtInfo->InFlightRDLen = txtInfo->QueuedRDLen;
2551*4b22b933Srs200217 info->OrigRData = txt->resrec.rdata;
2552*4b22b933Srs200217 info->OrigRDLen = txt->resrec.rdlength;
2553*4b22b933Srs200217 txtInfo->QueuedRData = mDNSNULL;
2554*4b22b933Srs200217 SendServiceRegistration(m, srs);
2555*4b22b933Srs200217 return;
2556*4b22b933Srs200217 }
2557*4b22b933Srs200217
2558*4b22b933Srs200217 m->mDNS_reentrancy++; // Increment to allow client to legally make mDNS API calls from the callback
2559*4b22b933Srs200217 if (InvokeCallback) srs->ServiceCallback(m, srs, err);
2560*4b22b933Srs200217 else if (info->ClientCallbackDeferred)
2561*4b22b933Srs200217 {
2562*4b22b933Srs200217 info->ClientCallbackDeferred = mDNSfalse;
2563*4b22b933Srs200217 srs->ServiceCallback(m, srs, info->DeferredStatus);
2564*4b22b933Srs200217 }
2565*4b22b933Srs200217 m->mDNS_reentrancy--; // Decrement to block mDNS API calls again
2566*4b22b933Srs200217 // NOTE: do not touch structures after calling ServiceCallback
2567*4b22b933Srs200217 }
2568*4b22b933Srs200217
hndlRecordUpdateReply(mDNS * m,AuthRecord * rr,mStatus err)2569*4b22b933Srs200217 mDNSlocal void hndlRecordUpdateReply(mDNS *m, AuthRecord *rr, mStatus err)
2570*4b22b933Srs200217 {
2571*4b22b933Srs200217 uDNS_RegInfo *info = &rr->uDNS_info;
2572*4b22b933Srs200217 mDNSBool InvokeCallback = mDNStrue;
2573*4b22b933Srs200217
2574*4b22b933Srs200217 if (info->state == regState_UpdatePending)
2575*4b22b933Srs200217 {
2576*4b22b933Srs200217 if (err)
2577*4b22b933Srs200217 {
2578*4b22b933Srs200217 LogMsg("Update record failed for %##s (err %d)", rr->resrec.name->c, err);
2579*4b22b933Srs200217 info->state = regState_Unregistered;
2580*4b22b933Srs200217 }
2581*4b22b933Srs200217 else
2582*4b22b933Srs200217 {
2583*4b22b933Srs200217 debugf("Update record %##s - success", rr->resrec.name->c);
2584*4b22b933Srs200217 info->state = regState_Registered;
2585*4b22b933Srs200217 // deallocate old RData
2586*4b22b933Srs200217 if (info->UpdateRDCallback) info->UpdateRDCallback(m, rr, info->OrigRData);
2587*4b22b933Srs200217 SetNewRData(&rr->resrec, info->InFlightRData, info->InFlightRDLen);
2588*4b22b933Srs200217 info->OrigRData = mDNSNULL;
2589*4b22b933Srs200217 info->InFlightRData = mDNSNULL;
2590*4b22b933Srs200217 }
2591*4b22b933Srs200217 }
2592*4b22b933Srs200217
2593*4b22b933Srs200217 if (info->state == regState_DeregPending)
2594*4b22b933Srs200217 {
2595*4b22b933Srs200217 debugf("Received reply for deregister record %##s type %d", rr->resrec.name->c, rr->resrec.rrtype);
2596*4b22b933Srs200217 if (err) LogMsg("ERROR: Deregistration of record %##s type %d failed with error %ld",
2597*4b22b933Srs200217 rr->resrec.name->c, rr->resrec.rrtype, err);
2598*4b22b933Srs200217 err = mStatus_MemFree;
2599*4b22b933Srs200217 info->state = regState_Unregistered;
2600*4b22b933Srs200217 }
2601*4b22b933Srs200217
2602*4b22b933Srs200217 if (info->state == regState_DeregDeferred)
2603*4b22b933Srs200217 {
2604*4b22b933Srs200217 if (err)
2605*4b22b933Srs200217 {
2606*4b22b933Srs200217 LogMsg("Cancelling deferred deregistration record %##s type %d due to registration error %ld",
2607*4b22b933Srs200217 rr->resrec.name->c, rr->resrec.rrtype, err);
2608*4b22b933Srs200217 info->state = regState_Unregistered;
2609*4b22b933Srs200217 }
2610*4b22b933Srs200217 debugf("Calling deferred deregistration of record %##s type %d", rr->resrec.name->c, rr->resrec.rrtype);
2611*4b22b933Srs200217 info->state = regState_Registered;
2612*4b22b933Srs200217 uDNS_DeregisterRecord(m, rr);
2613*4b22b933Srs200217 return;
2614*4b22b933Srs200217 }
2615*4b22b933Srs200217
2616*4b22b933Srs200217 if (info->state == regState_Pending || info->state == regState_Refresh)
2617*4b22b933Srs200217 {
2618*4b22b933Srs200217 if (!err)
2619*4b22b933Srs200217 {
2620*4b22b933Srs200217 info->state = regState_Registered;
2621*4b22b933Srs200217 if (info->state == regState_Refresh) InvokeCallback = mDNSfalse;
2622*4b22b933Srs200217 }
2623*4b22b933Srs200217 else
2624*4b22b933Srs200217 {
2625*4b22b933Srs200217 if (info->lease && err == mStatus_UnknownErr)
2626*4b22b933Srs200217 {
2627*4b22b933Srs200217 LogMsg("Re-trying update of record %##s without lease option", rr->resrec.name->c);
2628*4b22b933Srs200217 info->lease = mDNSfalse;
2629*4b22b933Srs200217 sendRecordRegistration(m, rr);
2630*4b22b933Srs200217 return;
2631*4b22b933Srs200217 }
2632*4b22b933Srs200217 LogMsg("Registration of record %##s type %d failed with error %ld", rr->resrec.name->c, rr->resrec.rrtype, err);
2633*4b22b933Srs200217 info->state = regState_Unregistered;
2634*4b22b933Srs200217 }
2635*4b22b933Srs200217 }
2636*4b22b933Srs200217
2637*4b22b933Srs200217 if (info->state == regState_Unregistered) unlinkAR(&m->uDNS_info.RecordRegistrations, rr);
2638*4b22b933Srs200217 else rr->ThisAPInterval = INIT_UCAST_POLL_INTERVAL - 1; // reset retry delay for future refreshes, dereg, etc.
2639*4b22b933Srs200217
2640*4b22b933Srs200217 if (info->QueuedRData && info->state == regState_Registered)
2641*4b22b933Srs200217 {
2642*4b22b933Srs200217 info->state = regState_UpdatePending;
2643*4b22b933Srs200217 info->InFlightRData = info->QueuedRData;
2644*4b22b933Srs200217 info->InFlightRDLen = info->QueuedRDLen;
2645*4b22b933Srs200217 info->OrigRData = rr->resrec.rdata;
2646*4b22b933Srs200217 info->OrigRDLen = rr->resrec.rdlength;
2647*4b22b933Srs200217 info->QueuedRData = mDNSNULL;
2648*4b22b933Srs200217 sendRecordRegistration(m, rr);
2649*4b22b933Srs200217 return;
2650*4b22b933Srs200217 }
2651*4b22b933Srs200217
2652*4b22b933Srs200217 if (InvokeCallback)
2653*4b22b933Srs200217 {
2654*4b22b933Srs200217 m->mDNS_reentrancy++; // Increment to allow client to legally make mDNS API calls from the callback
2655*4b22b933Srs200217 if (rr->RecordCallback) rr->RecordCallback(m, rr, err);
2656*4b22b933Srs200217 m->mDNS_reentrancy--; // Decrement to block mDNS API calls again
2657*4b22b933Srs200217 }
2658*4b22b933Srs200217 }
2659*4b22b933Srs200217
2660*4b22b933Srs200217
SetUpdateExpiration(mDNS * m,DNSMessage * msg,const mDNSu8 * end,uDNS_RegInfo * info)2661*4b22b933Srs200217 mDNSlocal void SetUpdateExpiration(mDNS *m, DNSMessage *msg, const mDNSu8 *end, uDNS_RegInfo *info)
2662*4b22b933Srs200217 {
2663*4b22b933Srs200217 LargeCacheRecord lcr;
2664*4b22b933Srs200217 const mDNSu8 *ptr;
2665*4b22b933Srs200217 int i;
2666*4b22b933Srs200217 mDNSu32 lease = 0;
2667*4b22b933Srs200217 mDNSs32 expire;
2668*4b22b933Srs200217
2669*4b22b933Srs200217 ptr = LocateAdditionals(msg, end);
2670*4b22b933Srs200217
2671*4b22b933Srs200217 if (info->lease && (ptr = LocateAdditionals(msg, end)))
2672*4b22b933Srs200217 {
2673*4b22b933Srs200217 for (i = 0; i < msg->h.numAdditionals; i++)
2674*4b22b933Srs200217 {
2675*4b22b933Srs200217 ptr = GetLargeResourceRecord(m, msg, ptr, end, 0, kDNSRecordTypePacketAdd, &lcr);
2676*4b22b933Srs200217 if (!ptr) break;
2677*4b22b933Srs200217 if (lcr.r.resrec.rrtype == kDNSType_OPT)
2678*4b22b933Srs200217 {
2679*4b22b933Srs200217 if (lcr.r.resrec.rdlength < LEASE_OPT_RDLEN) continue;
2680*4b22b933Srs200217 if (lcr.r.resrec.rdata->u.opt.opt != kDNSOpt_Lease) continue;
2681*4b22b933Srs200217 lease = lcr.r.resrec.rdata->u.opt.OptData.lease;
2682*4b22b933Srs200217 break;
2683*4b22b933Srs200217 }
2684*4b22b933Srs200217 }
2685*4b22b933Srs200217 }
2686*4b22b933Srs200217
2687*4b22b933Srs200217 if (lease > 0)
2688*4b22b933Srs200217 {
2689*4b22b933Srs200217 expire = (mDNSPlatformTimeNow(m) + (((mDNSs32)lease * mDNSPlatformOneSecond)) * 3/4);
2690*4b22b933Srs200217 if (info->state == regState_UpdatePending)
2691*4b22b933Srs200217 // if updating individual record, the service record set may expire sooner
2692*4b22b933Srs200217 { if (expire - info->expire < 0) info->expire = expire; }
2693*4b22b933Srs200217 else info->expire = expire;
2694*4b22b933Srs200217 }
2695*4b22b933Srs200217 else info->lease = mDNSfalse;
2696*4b22b933Srs200217 }
2697*4b22b933Srs200217
uDNS_ReceiveNATMap(mDNS * m,mDNSu8 * pkt,mDNSu16 len)2698*4b22b933Srs200217 mDNSexport void uDNS_ReceiveNATMap(mDNS *m, mDNSu8 *pkt, mDNSu16 len)
2699*4b22b933Srs200217 {
2700*4b22b933Srs200217 uDNS_GlobalInfo *u = &m->uDNS_info;
2701*4b22b933Srs200217 NATTraversalInfo *ptr = u->NATTraversals;
2702*4b22b933Srs200217 NATOp_t op;
2703*4b22b933Srs200217
2704*4b22b933Srs200217 // check length, version, opcode
2705*4b22b933Srs200217 if (len < sizeof(NATPortMapReply) && len < sizeof(NATAddrReply)) { LogMsg("NAT Traversal message too short (%d bytes)", len); return; }
2706*4b22b933Srs200217 if (pkt[0] != NATMAP_VERS) { LogMsg("Received NAT Traversal response with version %d (expect version %d)", pkt[0], NATMAP_VERS); return; }
2707*4b22b933Srs200217 op = pkt[1];
2708*4b22b933Srs200217 if (!(op & NATMAP_RESPONSE_MASK)) { LogMsg("Received NAT Traversal message that is not a response (opcode %d)", op); return; }
2709*4b22b933Srs200217
2710*4b22b933Srs200217 while (ptr)
2711*4b22b933Srs200217 {
2712*4b22b933Srs200217 if ((ptr->state == NATState_Request || ptr->state == NATState_Refresh) && (ptr->op | NATMAP_RESPONSE_MASK) == op)
2713*4b22b933Srs200217 if (ptr->ReceiveResponse(ptr, m, pkt, len)) break; // note callback may invalidate ptr if it return value is non-zero
2714*4b22b933Srs200217 ptr = ptr->next;
2715*4b22b933Srs200217 }
2716*4b22b933Srs200217 }
2717*4b22b933Srs200217
2718*4b22b933Srs200217 mDNSlocal const domainname *DNSRelayTestQuestion = (domainname*)
2719*4b22b933Srs200217 "\x1" "1" "\x1" "0" "\x1" "0" "\x3" "127" "\xa" "dnsbugtest"
2720*4b22b933Srs200217 "\x1" "1" "\x1" "0" "\x1" "0" "\x3" "127" "\x7" "in-addr" "\x4" "arpa";
2721*4b22b933Srs200217
2722*4b22b933Srs200217 // Returns mDNStrue if response was handled
uDNS_ReceiveTestQuestionResponse(mDNS * const m,DNSMessage * const msg,const mDNSu8 * const end,const mDNSAddr * const srcaddr,const mDNSInterfaceID InterfaceID)2723*4b22b933Srs200217 mDNSlocal mDNSBool uDNS_ReceiveTestQuestionResponse(mDNS *const m, DNSMessage *const msg, const mDNSu8 *const end,
2724*4b22b933Srs200217 const mDNSAddr *const srcaddr, const mDNSInterfaceID InterfaceID)
2725*4b22b933Srs200217 {
2726*4b22b933Srs200217 const mDNSu8 *ptr = msg->data;
2727*4b22b933Srs200217 DNSQuestion q;
2728*4b22b933Srs200217 DNSServer *s;
2729*4b22b933Srs200217 mDNSu32 result = 0;
2730*4b22b933Srs200217 mDNSBool found = mDNSfalse;
2731*4b22b933Srs200217
2732*4b22b933Srs200217 // 1. Find out if this is an answer to one of our test questions
2733*4b22b933Srs200217 if (msg->h.numQuestions != 1) return(mDNSfalse);
2734*4b22b933Srs200217 ptr = getQuestion(msg, ptr, end, InterfaceID, &q);
2735*4b22b933Srs200217 if (!ptr) return(mDNSfalse);
2736*4b22b933Srs200217 if (q.qtype != kDNSType_PTR || q.qclass != kDNSClass_IN) return(mDNSfalse);
2737*4b22b933Srs200217 if (!SameDomainName(&q.qname, DNSRelayTestQuestion)) return(mDNSfalse);
2738*4b22b933Srs200217
2739*4b22b933Srs200217 // 2. If the DNS relay gave us a positive response, then it's got buggy firmware
2740*4b22b933Srs200217 // else, if the DNS relay gave us an error or no-answer response, it passed our test
2741*4b22b933Srs200217 if ((msg->h.flags.b[1] & kDNSFlag1_RC) == kDNSFlag1_RC_NoErr && msg->h.numAnswers > 0)
2742*4b22b933Srs200217 result = DNSServer_Failed;
2743*4b22b933Srs200217 else
2744*4b22b933Srs200217 result = DNSServer_Passed;
2745*4b22b933Srs200217
2746*4b22b933Srs200217 // 3. Find occurrences of this server in our list, and mark them appropriately
2747*4b22b933Srs200217 for (s = m->uDNS_info.Servers; s; s = s->next)
2748*4b22b933Srs200217 if (mDNSSameAddress(srcaddr, &s->addr) && s->teststate != result)
2749*4b22b933Srs200217 { s->teststate = result; found = mDNStrue; }
2750*4b22b933Srs200217
2751*4b22b933Srs200217 // 4. Assuming we found the server in question in our list (don't want to risk being victim of a deliberate DOS attack here)
2752*4b22b933Srs200217 // log a message to let the user know why Wide-Area Service Discovery isn't working
2753*4b22b933Srs200217 if (found && result == DNSServer_Failed)
2754*4b22b933Srs200217 LogMsg("NOTE: Wide-Area Service Discovery disabled to avoid crashing defective DNS relay %#a.", srcaddr);
2755*4b22b933Srs200217
2756*4b22b933Srs200217 return(mDNStrue); // Return mDNStrue to tell uDNS_ReceiveMsg it doens't need to process this packet further
2757*4b22b933Srs200217 }
2758*4b22b933Srs200217
uDNS_ReceiveMsg(mDNS * const m,DNSMessage * const msg,const mDNSu8 * const end,const mDNSAddr * const srcaddr,const mDNSIPPort srcport,const mDNSAddr * const dstaddr,const mDNSIPPort dstport,const mDNSInterfaceID InterfaceID)2759*4b22b933Srs200217 mDNSexport void uDNS_ReceiveMsg(mDNS *const m, DNSMessage *const msg, const mDNSu8 *const end,
2760*4b22b933Srs200217 const mDNSAddr *const srcaddr, const mDNSIPPort srcport, const mDNSAddr *const dstaddr,
2761*4b22b933Srs200217 const mDNSIPPort dstport, const mDNSInterfaceID InterfaceID)
2762*4b22b933Srs200217 {
2763*4b22b933Srs200217 DNSQuestion *qptr;
2764*4b22b933Srs200217 AuthRecord *rptr;
2765*4b22b933Srs200217 ServiceRecordSet *sptr;
2766*4b22b933Srs200217 mStatus err = mStatus_NoError;
2767*4b22b933Srs200217 uDNS_GlobalInfo *u = &m->uDNS_info;
2768*4b22b933Srs200217
2769*4b22b933Srs200217 mDNSu8 StdR = kDNSFlag0_QR_Response | kDNSFlag0_OP_StdQuery;
2770*4b22b933Srs200217 mDNSu8 UpdateR = kDNSFlag0_QR_Response | kDNSFlag0_OP_Update;
2771*4b22b933Srs200217 mDNSu8 QR_OP = (mDNSu8)(msg->h.flags.b[0] & kDNSFlag0_QROP_Mask);
2772*4b22b933Srs200217 mDNSu8 rcode = (mDNSu8)(msg->h.flags.b[1] & kDNSFlag1_RC);
2773*4b22b933Srs200217
2774*4b22b933Srs200217 mDNSs32 timenow = mDNSPlatformTimeNow(m);
2775*4b22b933Srs200217
2776*4b22b933Srs200217 // unused
2777*4b22b933Srs200217 (void)dstaddr;
2778*4b22b933Srs200217 (void)dstport;
2779*4b22b933Srs200217 (void)InterfaceID;
2780*4b22b933Srs200217
2781*4b22b933Srs200217 if (QR_OP == StdR)
2782*4b22b933Srs200217 {
2783*4b22b933Srs200217 // !!!KRS we should to a table lookup here to see if it answers an LLQ or a 1-shot
2784*4b22b933Srs200217 // LLQ Responses over TCP not currently supported
2785*4b22b933Srs200217 if (srcaddr && recvLLQResponse(m, msg, end, srcaddr, srcport, InterfaceID)) return;
2786*4b22b933Srs200217
2787*4b22b933Srs200217 if (uDNS_ReceiveTestQuestionResponse(m, msg, end, srcaddr, InterfaceID)) return;
2788*4b22b933Srs200217
2789*4b22b933Srs200217 for (qptr = u->ActiveQueries; qptr; qptr = qptr->next)
2790*4b22b933Srs200217 {
2791*4b22b933Srs200217 //!!!KRS we should have a hashtable, hashed on message id
2792*4b22b933Srs200217 if (qptr->uDNS_info.id.NotAnInteger == msg->h.id.NotAnInteger)
2793*4b22b933Srs200217 {
2794*4b22b933Srs200217 if (timenow - (qptr->LastQTime + RESPONSE_WINDOW) > 0)
2795*4b22b933Srs200217 { debugf("uDNS_ReceiveMsg - response received after maximum allowed window. Discarding"); return; }
2796*4b22b933Srs200217 if (msg->h.flags.b[0] & kDNSFlag0_TC)
2797*4b22b933Srs200217 { hndlTruncatedAnswer(qptr, srcaddr, m); return; }
2798*4b22b933Srs200217 else
2799*4b22b933Srs200217 {
2800*4b22b933Srs200217 u->CurrentQuery = qptr;
2801*4b22b933Srs200217 qptr->uDNS_info.responseCallback(m, msg, end, qptr, qptr->uDNS_info.context);
2802*4b22b933Srs200217 u->CurrentQuery = mDNSNULL;
2803*4b22b933Srs200217 // Note: responseCallback can invalidate qptr
2804*4b22b933Srs200217 return;
2805*4b22b933Srs200217 }
2806*4b22b933Srs200217 }
2807*4b22b933Srs200217 }
2808*4b22b933Srs200217 }
2809*4b22b933Srs200217 if (QR_OP == UpdateR)
2810*4b22b933Srs200217 {
2811*4b22b933Srs200217 for (sptr = u->ServiceRegistrations; sptr; sptr = sptr->next)
2812*4b22b933Srs200217 {
2813*4b22b933Srs200217 if (sptr->uDNS_info.id.NotAnInteger == msg->h.id.NotAnInteger)
2814*4b22b933Srs200217 {
2815*4b22b933Srs200217 err = checkUpdateResult(sptr->RR_SRV.resrec.name, rcode, m, msg, end);
2816*4b22b933Srs200217 if (!err) SetUpdateExpiration(m, msg, end, &sptr->uDNS_info);
2817*4b22b933Srs200217 hndlServiceUpdateReply(m, sptr, err);
2818*4b22b933Srs200217 return;
2819*4b22b933Srs200217 }
2820*4b22b933Srs200217 }
2821*4b22b933Srs200217 for (rptr = u->RecordRegistrations; rptr; rptr = rptr->next)
2822*4b22b933Srs200217 {
2823*4b22b933Srs200217 if (rptr->uDNS_info.id.NotAnInteger == msg->h.id.NotAnInteger)
2824*4b22b933Srs200217 {
2825*4b22b933Srs200217 err = checkUpdateResult(rptr->resrec.name, rcode, m, msg, end);
2826*4b22b933Srs200217 if (!err) SetUpdateExpiration(m, msg, end, &rptr->uDNS_info);
2827*4b22b933Srs200217 hndlRecordUpdateReply(m, rptr, err);
2828*4b22b933Srs200217 return;
2829*4b22b933Srs200217 }
2830*4b22b933Srs200217 }
2831*4b22b933Srs200217 }
2832*4b22b933Srs200217 debugf("Received unexpected response: ID %d matches no active records", mDNSVal16(msg->h.id));
2833*4b22b933Srs200217 }
2834*4b22b933Srs200217
2835*4b22b933Srs200217 // lookup a DNS Server, matching by name in split-dns configurations. Result stored in addr parameter if successful
GetServerForName(uDNS_GlobalInfo * u,const domainname * name)2836*4b22b933Srs200217 mDNSlocal DNSServer *GetServerForName(uDNS_GlobalInfo *u, const domainname *name)
2837*4b22b933Srs200217 {
2838*4b22b933Srs200217 DNSServer *curmatch = mDNSNULL, *p = u->Servers;
2839*4b22b933Srs200217 int i, curmatchlen = -1;
2840*4b22b933Srs200217 int ncount = name ? CountLabels(name) : 0;
2841*4b22b933Srs200217
2842*4b22b933Srs200217 while (p)
2843*4b22b933Srs200217 {
2844*4b22b933Srs200217 int scount = CountLabels(&p->domain);
2845*4b22b933Srs200217 if (scount <= ncount && scount > curmatchlen)
2846*4b22b933Srs200217 {
2847*4b22b933Srs200217 // only inspect if server's domain is longer than current best match and shorter than the name itself
2848*4b22b933Srs200217 const domainname *tail = name;
2849*4b22b933Srs200217 for (i = 0; i < ncount - scount; i++)
2850*4b22b933Srs200217 tail = (domainname *)(tail->c + 1 + tail->c[0]); // find "tail" (scount labels) of name
2851*4b22b933Srs200217 if (SameDomainName(tail, &p->domain)) { curmatch = p; curmatchlen = scount; }
2852*4b22b933Srs200217 }
2853*4b22b933Srs200217 p = p->next;
2854*4b22b933Srs200217 }
2855*4b22b933Srs200217 return(curmatch);
2856*4b22b933Srs200217 }
2857*4b22b933Srs200217
2858*4b22b933Srs200217 // ***************************************************************************
2859*4b22b933Srs200217 #if COMPILER_LIKES_PRAGMA_MARK
2860*4b22b933Srs200217 #pragma mark - Query Routines
2861*4b22b933Srs200217 #endif
2862*4b22b933Srs200217
2863*4b22b933Srs200217 #define sameID(x,y) mDNSPlatformMemSame(x,y,8)
2864*4b22b933Srs200217
initializeQuery(DNSMessage * msg,DNSQuestion * question)2865*4b22b933Srs200217 mDNSlocal void initializeQuery(DNSMessage *msg, DNSQuestion *question)
2866*4b22b933Srs200217 {
2867*4b22b933Srs200217 ubzero(msg, sizeof(msg));
2868*4b22b933Srs200217 InitializeDNSMessage(&msg->h, question->uDNS_info.id, uQueryFlags);
2869*4b22b933Srs200217 }
2870*4b22b933Srs200217
constructQueryMsg(DNSMessage * msg,mDNSu8 ** endPtr,DNSQuestion * const question)2871*4b22b933Srs200217 mDNSlocal mStatus constructQueryMsg(DNSMessage *msg, mDNSu8 **endPtr, DNSQuestion *const question)
2872*4b22b933Srs200217 {
2873*4b22b933Srs200217 initializeQuery(msg, question);
2874*4b22b933Srs200217
2875*4b22b933Srs200217 *endPtr = putQuestion(msg, msg->data, msg->data + AbsoluteMaxDNSMessageData, &question->qname, question->qtype, question->qclass);
2876*4b22b933Srs200217 if (!*endPtr)
2877*4b22b933Srs200217 {
2878*4b22b933Srs200217 LogMsg("ERROR: Unicast query out of space in packet");
2879*4b22b933Srs200217 return mStatus_UnknownErr;
2880*4b22b933Srs200217 }
2881*4b22b933Srs200217 return mStatus_NoError;
2882*4b22b933Srs200217 }
2883*4b22b933Srs200217
putLLQ(DNSMessage * const msg,mDNSu8 * ptr,DNSQuestion * question,LLQOptData * data,mDNSBool includeQuestion)2884*4b22b933Srs200217 mDNSlocal mDNSu8 *putLLQ(DNSMessage *const msg, mDNSu8 *ptr, DNSQuestion *question, LLQOptData *data, mDNSBool includeQuestion)
2885*4b22b933Srs200217 {
2886*4b22b933Srs200217 AuthRecord rr;
2887*4b22b933Srs200217 ResourceRecord *opt = &rr.resrec;
2888*4b22b933Srs200217 rdataOpt *optRD;
2889*4b22b933Srs200217
2890*4b22b933Srs200217 //!!!KRS when we implement multiple llqs per message, we'll need to memmove anything past the question section
2891*4b22b933Srs200217 if (includeQuestion)
2892*4b22b933Srs200217 {
2893*4b22b933Srs200217 ptr = putQuestion(msg, ptr, msg->data + AbsoluteMaxDNSMessageData, &question->qname, question->qtype, question->qclass);
2894*4b22b933Srs200217 if (!ptr) { LogMsg("ERROR: putLLQ - putQuestion"); return mDNSNULL; }
2895*4b22b933Srs200217 }
2896*4b22b933Srs200217 // locate OptRR if it exists, set pointer to end
2897*4b22b933Srs200217 // !!!KRS implement me
2898*4b22b933Srs200217
2899*4b22b933Srs200217
2900*4b22b933Srs200217 // format opt rr (fields not specified are zero-valued)
2901*4b22b933Srs200217 ubzero(&rr, sizeof(AuthRecord));
2902*4b22b933Srs200217 mDNS_SetupResourceRecord(&rr, mDNSNULL, mDNSInterface_Any, kDNSType_OPT, kStandardTTL, kDNSRecordTypeKnownUnique, mDNSNULL, mDNSNULL);
2903*4b22b933Srs200217 opt->rdlength = LLQ_OPT_RDLEN;
2904*4b22b933Srs200217 opt->rdestimate = LLQ_OPT_RDLEN;
2905*4b22b933Srs200217
2906*4b22b933Srs200217 optRD = &rr.resrec.rdata->u.opt;
2907*4b22b933Srs200217 optRD->opt = kDNSOpt_LLQ;
2908*4b22b933Srs200217 optRD->optlen = LLQ_OPTLEN;
2909*4b22b933Srs200217 umemcpy(&optRD->OptData.llq, data, sizeof(*data));
2910*4b22b933Srs200217 ptr = PutResourceRecordTTLJumbo(msg, ptr, &msg->h.numAdditionals, opt, 0);
2911*4b22b933Srs200217 if (!ptr) { LogMsg("ERROR: putLLQ - PutResourceRecordTTLJumbo"); return mDNSNULL; }
2912*4b22b933Srs200217
2913*4b22b933Srs200217 return ptr;
2914*4b22b933Srs200217 }
2915*4b22b933Srs200217
2916*4b22b933Srs200217
getLLQAtIndex(mDNS * m,DNSMessage * msg,const mDNSu8 * end,LLQOptData * llq,int index)2917*4b22b933Srs200217 mDNSlocal mDNSBool getLLQAtIndex(mDNS *m, DNSMessage *msg, const mDNSu8 *end, LLQOptData *llq, int index)
2918*4b22b933Srs200217 {
2919*4b22b933Srs200217 LargeCacheRecord lcr;
2920*4b22b933Srs200217 int i;
2921*4b22b933Srs200217 const mDNSu8 *ptr;
2922*4b22b933Srs200217
2923*4b22b933Srs200217 ubzero(&lcr, sizeof(lcr));
2924*4b22b933Srs200217
2925*4b22b933Srs200217 ptr = LocateAdditionals(msg, end);
2926*4b22b933Srs200217 if (!ptr) return mDNSfalse;
2927*4b22b933Srs200217
2928*4b22b933Srs200217 // find the last additional
2929*4b22b933Srs200217 for (i = 0; i < msg->h.numAdditionals; i++)
2930*4b22b933Srs200217 // { ptr = GetLargeResourceRecord(m, msg, ptr, end, 0, kDNSRecordTypePacketAdd, &lcr); if (!ptr) return mDNSfalse; }
2931*4b22b933Srs200217 //!!!KRS workaround for LH server bug, which puts OPT as first additional
2932*4b22b933Srs200217 { ptr = GetLargeResourceRecord(m, msg, ptr, end, 0, kDNSRecordTypePacketAdd, &lcr); if (!ptr) return mDNSfalse; if (lcr.r.resrec.rrtype == kDNSType_OPT) break; }
2933*4b22b933Srs200217 if (lcr.r.resrec.rrtype != kDNSType_OPT) return mDNSfalse;
2934*4b22b933Srs200217 if (lcr.r.resrec.rdlength < (index + 1) * LLQ_OPT_RDLEN) return mDNSfalse; // rdata too small
2935*4b22b933Srs200217 umemcpy(llq, (mDNSu8 *)&lcr.r.resrec.rdata->u.opt.OptData.llq + (index * sizeof(*llq)), sizeof(*llq));
2936*4b22b933Srs200217 return mDNStrue;
2937*4b22b933Srs200217 }
2938*4b22b933Srs200217
recvRefreshReply(mDNS * m,DNSMessage * msg,const mDNSu8 * end,DNSQuestion * q)2939*4b22b933Srs200217 mDNSlocal void recvRefreshReply(mDNS *m, DNSMessage *msg, const mDNSu8 *end, DNSQuestion *q)
2940*4b22b933Srs200217 {
2941*4b22b933Srs200217 LLQ_Info *qInfo;
2942*4b22b933Srs200217 LLQOptData pktData;
2943*4b22b933Srs200217
2944*4b22b933Srs200217 qInfo = q->uDNS_info.llq;
2945*4b22b933Srs200217 if (!getLLQAtIndex(m, msg, end, &pktData, 0)) { LogMsg("ERROR recvRefreshReply - getLLQAtIndex"); return; }
2946*4b22b933Srs200217 if (pktData.llqOp != kLLQOp_Refresh) return;
2947*4b22b933Srs200217 if (!sameID(pktData.id, qInfo->id)) { LogMsg("recvRefreshReply - ID mismatch. Discarding"); return; }
2948*4b22b933Srs200217 if (pktData.err != LLQErr_NoError) { LogMsg("recvRefreshReply: received error %d from server", pktData.err); return; }
2949*4b22b933Srs200217
2950*4b22b933Srs200217 qInfo->expire = mDNSPlatformTimeNow(m) + ((mDNSs32)pktData.lease * mDNSPlatformOneSecond);
2951*4b22b933Srs200217 qInfo->retry = qInfo->expire - ((mDNSs32)pktData.lease * mDNSPlatformOneSecond/2);
2952*4b22b933Srs200217
2953*4b22b933Srs200217 qInfo->origLease = pktData.lease;
2954*4b22b933Srs200217 qInfo->state = LLQ_Established;
2955*4b22b933Srs200217 }
2956*4b22b933Srs200217
sendLLQRefresh(mDNS * m,DNSQuestion * q,mDNSu32 lease)2957*4b22b933Srs200217 mDNSlocal void sendLLQRefresh(mDNS *m, DNSQuestion *q, mDNSu32 lease)
2958*4b22b933Srs200217 {
2959*4b22b933Srs200217 DNSMessage msg;
2960*4b22b933Srs200217 mDNSu8 *end;
2961*4b22b933Srs200217 LLQOptData llq;
2962*4b22b933Srs200217 LLQ_Info *info = q->uDNS_info.llq;
2963*4b22b933Srs200217 mStatus err;
2964*4b22b933Srs200217 mDNSs32 timenow;
2965*4b22b933Srs200217
2966*4b22b933Srs200217 timenow = mDNSPlatformTimeNow(m);
2967*4b22b933Srs200217 if ((info->state == LLQ_Refresh && info->ntries >= kLLQ_MAX_TRIES) ||
2968*4b22b933Srs200217 info->expire - timenow < 0)
2969*4b22b933Srs200217 {
2970*4b22b933Srs200217 LogMsg("Unable to refresh LLQ %##s - will retry in %d minutes", q->qname.c, kLLQ_DEF_RETRY/60);
2971*4b22b933Srs200217 info->state = LLQ_Retry;
2972*4b22b933Srs200217 info->retry = mDNSPlatformTimeNow(m) + kLLQ_DEF_RETRY * mDNSPlatformOneSecond;
2973*4b22b933Srs200217 info->deriveRemovesOnResume = mDNStrue;
2974*4b22b933Srs200217 return;
2975*4b22b933Srs200217 //!!!KRS handle this - periodically try to re-establish
2976*4b22b933Srs200217 }
2977*4b22b933Srs200217
2978*4b22b933Srs200217 llq.vers = kLLQ_Vers;
2979*4b22b933Srs200217 llq.llqOp = kLLQOp_Refresh;
2980*4b22b933Srs200217 llq.err = LLQErr_NoError;
2981*4b22b933Srs200217 umemcpy(llq.id, info->id, 8);
2982*4b22b933Srs200217 llq.lease = lease;
2983*4b22b933Srs200217
2984*4b22b933Srs200217 initializeQuery(&msg, q);
2985*4b22b933Srs200217 end = putLLQ(&msg, msg.data, q, &llq, mDNStrue);
2986*4b22b933Srs200217 if (!end) { LogMsg("ERROR: sendLLQRefresh - putLLQ"); return; }
2987*4b22b933Srs200217
2988*4b22b933Srs200217 err = mDNSSendDNSMessage(m, &msg, end, mDNSInterface_Any, &info->servAddr, info->servPort, -1, mDNSNULL);
2989*4b22b933Srs200217 if (err) debugf("ERROR: sendLLQRefresh - mDNSSendDNSMessage returned %ld", err);
2990*4b22b933Srs200217
2991*4b22b933Srs200217 if (info->state == LLQ_Established) info->ntries = 1;
2992*4b22b933Srs200217 else info->ntries++;
2993*4b22b933Srs200217 info->state = LLQ_Refresh;
2994*4b22b933Srs200217 q->LastQTime = timenow;
2995*4b22b933Srs200217 info->retry = (info->expire - q->LastQTime) / 2;
2996*4b22b933Srs200217 }
2997*4b22b933Srs200217
recvLLQEvent(mDNS * m,DNSQuestion * q,DNSMessage * msg,const mDNSu8 * end,const mDNSAddr * srcaddr,mDNSIPPort srcport,mDNSInterfaceID InterfaceID)2998*4b22b933Srs200217 mDNSlocal mDNSBool recvLLQEvent(mDNS *m, DNSQuestion *q, DNSMessage *msg, const mDNSu8 *end, const mDNSAddr *srcaddr, mDNSIPPort srcport, mDNSInterfaceID InterfaceID)
2999*4b22b933Srs200217 {
3000*4b22b933Srs200217 DNSMessage ack;
3001*4b22b933Srs200217 mDNSu8 *ackEnd = ack.data;
3002*4b22b933Srs200217 mStatus err;
3003*4b22b933Srs200217 LLQOptData opt;
3004*4b22b933Srs200217
3005*4b22b933Srs200217 (void)InterfaceID; // unused
3006*4b22b933Srs200217
3007*4b22b933Srs200217 // find Opt RR, verify correct ID
3008*4b22b933Srs200217 if (!getLLQAtIndex(m, msg, end, &opt, 0)) { debugf("Pkt does not contain LLQ Opt"); return mDNSfalse; }
3009*4b22b933Srs200217 if (!q->uDNS_info.llq) { LogMsg("Error: recvLLQEvent - question object does not contain LLQ metadata"); return mDNSfalse; }
3010*4b22b933Srs200217 if (!sameID(opt.id, q->uDNS_info.llq->id)) { return mDNSfalse; }
3011*4b22b933Srs200217 if (opt.llqOp != kLLQOp_Event) { if (!q->uDNS_info.llq->ntries) LogMsg("recvLLQEvent - Bad LLQ Opcode %d", opt.llqOp); return mDNSfalse; }
3012*4b22b933Srs200217
3013*4b22b933Srs200217 // invoke response handler
3014*4b22b933Srs200217 m->uDNS_info.CurrentQuery = q;
3015*4b22b933Srs200217 q->uDNS_info.responseCallback(m, msg, end, q, q->uDNS_info.context);
3016*4b22b933Srs200217 if (m->uDNS_info.CurrentQuery != q) return mDNStrue;
3017*4b22b933Srs200217
3018*4b22b933Srs200217 // format and send ack
3019*4b22b933Srs200217 InitializeDNSMessage(&ack.h, msg->h.id, ResponseFlags);
3020*4b22b933Srs200217 ackEnd = putLLQ(&ack, ack.data, mDNSNULL, &opt, mDNSfalse);
3021*4b22b933Srs200217 if (!ackEnd) { LogMsg("ERROR: recvLLQEvent - putLLQ"); return mDNSfalse; }
3022*4b22b933Srs200217 err = mDNSSendDNSMessage(m, &ack, ackEnd, mDNSInterface_Any, srcaddr, srcport, -1, mDNSNULL);
3023*4b22b933Srs200217 if (err) debugf("ERROR: recvLLQEvent - mDNSSendDNSMessage returned %ld", err);
3024*4b22b933Srs200217 return mDNStrue;
3025*4b22b933Srs200217 }
3026*4b22b933Srs200217
3027*4b22b933Srs200217
3028*4b22b933Srs200217
hndlChallengeResponseAck(mDNS * m,DNSMessage * pktMsg,const mDNSu8 * end,LLQOptData * llq,DNSQuestion * q)3029*4b22b933Srs200217 mDNSlocal void hndlChallengeResponseAck(mDNS *m, DNSMessage *pktMsg, const mDNSu8 *end, LLQOptData *llq, DNSQuestion *q)
3030*4b22b933Srs200217 {
3031*4b22b933Srs200217 LLQ_Info *info = q->uDNS_info.llq;
3032*4b22b933Srs200217
3033*4b22b933Srs200217 if (llq->err) { LogMsg("hndlChallengeResponseAck - received error %d from server", llq->err); goto error; }
3034*4b22b933Srs200217 if (!sameID(info->id, llq->id)) { LogMsg("hndlChallengeResponseAck - ID changed. discarding"); return; } // this can happen rarely (on packet loss + reordering)
3035*4b22b933Srs200217 info->expire = mDNSPlatformTimeNow(m) + ((mDNSs32)llq->lease * mDNSPlatformOneSecond);
3036*4b22b933Srs200217 info->retry = info->expire - ((mDNSs32)llq->lease * mDNSPlatformOneSecond / 2);
3037*4b22b933Srs200217
3038*4b22b933Srs200217 info->origLease = llq->lease;
3039*4b22b933Srs200217 info->state = LLQ_Established;
3040*4b22b933Srs200217
3041*4b22b933Srs200217 q->uDNS_info.responseCallback = llqResponseHndlr;
3042*4b22b933Srs200217 llqResponseHndlr(m, pktMsg, end, q, mDNSNULL);
3043*4b22b933Srs200217 return;
3044*4b22b933Srs200217
3045*4b22b933Srs200217 error:
3046*4b22b933Srs200217 info->state = LLQ_Error;
3047*4b22b933Srs200217 }
3048*4b22b933Srs200217
sendChallengeResponse(mDNS * m,DNSQuestion * q,LLQOptData * llq)3049*4b22b933Srs200217 mDNSlocal void sendChallengeResponse(mDNS *m, DNSQuestion *q, LLQOptData *llq)
3050*4b22b933Srs200217 {
3051*4b22b933Srs200217 LLQ_Info *info = q->uDNS_info.llq;
3052*4b22b933Srs200217 DNSMessage response;
3053*4b22b933Srs200217 mDNSu8 *responsePtr = response.data;
3054*4b22b933Srs200217 mStatus err;
3055*4b22b933Srs200217 LLQOptData llqBuf;
3056*4b22b933Srs200217 mDNSs32 timenow = mDNSPlatformTimeNow(m);
3057*4b22b933Srs200217
3058*4b22b933Srs200217 if (info->ntries++ == kLLQ_MAX_TRIES)
3059*4b22b933Srs200217 {
3060*4b22b933Srs200217 LogMsg("sendChallengeResponse: %d failed attempts for LLQ %##s. Will re-try in %d minutes",
3061*4b22b933Srs200217 kLLQ_MAX_TRIES, q->qname.c, kLLQ_DEF_RETRY / 60);
3062*4b22b933Srs200217 info->state = LLQ_Retry;
3063*4b22b933Srs200217 info->retry = timenow + (kLLQ_DEF_RETRY * mDNSPlatformOneSecond);
3064*4b22b933Srs200217 // !!!KRS give a callback error in these cases?
3065*4b22b933Srs200217 return;
3066*4b22b933Srs200217 }
3067*4b22b933Srs200217
3068*4b22b933Srs200217 if (!llq)
3069*4b22b933Srs200217 {
3070*4b22b933Srs200217 llq = &llqBuf;
3071*4b22b933Srs200217 llq->vers = kLLQ_Vers;
3072*4b22b933Srs200217 llq->llqOp = kLLQOp_Setup;
3073*4b22b933Srs200217 llq->err = LLQErr_NoError;
3074*4b22b933Srs200217 umemcpy(llq->id, info->id, 8);
3075*4b22b933Srs200217 llq->lease = info->origLease;
3076*4b22b933Srs200217 }
3077*4b22b933Srs200217
3078*4b22b933Srs200217 q->LastQTime = timenow;
3079*4b22b933Srs200217 info->retry = timenow + (kLLQ_INIT_RESEND * info->ntries * mDNSPlatformOneSecond);
3080*4b22b933Srs200217
3081*4b22b933Srs200217 if (constructQueryMsg(&response, &responsePtr, q)) goto error;
3082*4b22b933Srs200217 responsePtr = putLLQ(&response, responsePtr, q, llq, mDNSfalse);
3083*4b22b933Srs200217 if (!responsePtr) { LogMsg("ERROR: sendChallengeResponse - putLLQ"); goto error; }
3084*4b22b933Srs200217
3085*4b22b933Srs200217 err = mDNSSendDNSMessage(m, &response, responsePtr, mDNSInterface_Any, &info->servAddr, info->servPort, -1, mDNSNULL);
3086*4b22b933Srs200217 if (err) debugf("ERROR: sendChallengeResponse - mDNSSendDNSMessage returned %ld", err);
3087*4b22b933Srs200217 // on error, we procede as normal and retry after the appropriate interval
3088*4b22b933Srs200217
3089*4b22b933Srs200217 return;
3090*4b22b933Srs200217
3091*4b22b933Srs200217 error:
3092*4b22b933Srs200217 info->state = LLQ_Error;
3093*4b22b933Srs200217 }
3094*4b22b933Srs200217
3095*4b22b933Srs200217
3096*4b22b933Srs200217
hndlRequestChallenge(mDNS * m,DNSMessage * pktMsg,const mDNSu8 * end,LLQOptData * llq,DNSQuestion * q)3097*4b22b933Srs200217 mDNSlocal void hndlRequestChallenge(mDNS *m, DNSMessage *pktMsg, const mDNSu8 *end, LLQOptData *llq, DNSQuestion *q)
3098*4b22b933Srs200217 {
3099*4b22b933Srs200217 LLQ_Info *info = q->uDNS_info.llq;
3100*4b22b933Srs200217 mDNSs32 timenow = mDNSPlatformTimeNow(m);
3101*4b22b933Srs200217 switch(llq->err)
3102*4b22b933Srs200217 {
3103*4b22b933Srs200217 case LLQErr_NoError: break;
3104*4b22b933Srs200217 case LLQErr_ServFull:
3105*4b22b933Srs200217 LogMsg("hndlRequestChallenge - received ServFull from server for LLQ %##s. Retry in %lu sec", q->qname.c, llq->lease);
3106*4b22b933Srs200217 info->retry = timenow + ((mDNSs32)llq->lease * mDNSPlatformOneSecond);
3107*4b22b933Srs200217 info->state = LLQ_Retry;
3108*4b22b933Srs200217 simpleResponseHndlr(m, pktMsg, end, q, mDNSNULL); // get available answers
3109*4b22b933Srs200217 info->deriveRemovesOnResume = mDNStrue;
3110*4b22b933Srs200217 case LLQErr_Static:
3111*4b22b933Srs200217 info->state = LLQ_Static;
3112*4b22b933Srs200217 LogMsg("LLQ %##s: static", q->qname.c);
3113*4b22b933Srs200217 simpleResponseHndlr(m, pktMsg, end, q, mDNSNULL);
3114*4b22b933Srs200217 return;
3115*4b22b933Srs200217 case LLQErr_FormErr:
3116*4b22b933Srs200217 LogMsg("ERROR: hndlRequestChallenge - received FormErr from server for LLQ %##s", q->qname.c);
3117*4b22b933Srs200217 goto error;
3118*4b22b933Srs200217 case LLQErr_BadVers:
3119*4b22b933Srs200217 LogMsg("ERROR: hndlRequestChallenge - received BadVers from server");
3120*4b22b933Srs200217 goto error;
3121*4b22b933Srs200217 case LLQErr_UnknownErr:
3122*4b22b933Srs200217 LogMsg("ERROR: hndlRequestChallenge - received UnknownErr from server for LLQ %##s", q->qname.c);
3123*4b22b933Srs200217 goto error;
3124*4b22b933Srs200217 default:
3125*4b22b933Srs200217 LogMsg("ERROR: hndlRequestChallenge - received invalid error %d for LLQ %##s", llq->err, q->qname.c);
3126*4b22b933Srs200217 goto error;
3127*4b22b933Srs200217 }
3128*4b22b933Srs200217
3129*4b22b933Srs200217 if (info->origLease != llq->lease)
3130*4b22b933Srs200217 debugf("hndlRequestChallenge: requested lease %lu, granted lease %lu", info->origLease, llq->lease);
3131*4b22b933Srs200217
3132*4b22b933Srs200217 // cache expiration in case we go to sleep before finishing setup
3133*4b22b933Srs200217 info->origLease = llq->lease;
3134*4b22b933Srs200217 info->expire = timenow + ((mDNSs32)llq->lease * mDNSPlatformOneSecond);
3135*4b22b933Srs200217
3136*4b22b933Srs200217 // update state
3137*4b22b933Srs200217 info->state = LLQ_SecondaryRequest;
3138*4b22b933Srs200217 umemcpy(info->id, llq->id, 8);
3139*4b22b933Srs200217 info->ntries = 0; // first attempt to send response
3140*4b22b933Srs200217
3141*4b22b933Srs200217 sendChallengeResponse(m, q, llq);
3142*4b22b933Srs200217 return;
3143*4b22b933Srs200217
3144*4b22b933Srs200217
3145*4b22b933Srs200217 error:
3146*4b22b933Srs200217 info->state = LLQ_Error;
3147*4b22b933Srs200217 }
3148*4b22b933Srs200217
3149*4b22b933Srs200217
3150*4b22b933Srs200217 // response handler for initial and secondary setup responses
recvSetupResponse(mDNS * m,DNSMessage * pktMsg,const mDNSu8 * end,DNSQuestion * q,void * clientContext)3151*4b22b933Srs200217 mDNSlocal void recvSetupResponse(mDNS *m, DNSMessage *pktMsg, const mDNSu8 *end, DNSQuestion *q, void *clientContext)
3152*4b22b933Srs200217 {
3153*4b22b933Srs200217 DNSQuestion pktQuestion;
3154*4b22b933Srs200217 LLQOptData llq;
3155*4b22b933Srs200217 const mDNSu8 *ptr = pktMsg->data;
3156*4b22b933Srs200217 LLQ_Info *info = q->uDNS_info.llq;
3157*4b22b933Srs200217 mDNSu8 rcode = (mDNSu8)(pktMsg->h.flags.b[1] & kDNSFlag1_RC);
3158*4b22b933Srs200217
3159*4b22b933Srs200217 (void)clientContext; // unused
3160*4b22b933Srs200217
3161*4b22b933Srs200217 if (rcode && rcode != kDNSFlag1_RC_NXDomain) goto poll;
3162*4b22b933Srs200217
3163*4b22b933Srs200217 ptr = getQuestion(pktMsg, ptr, end, 0, &pktQuestion);
3164*4b22b933Srs200217 if (!ptr) { LogMsg("ERROR: recvSetupResponse - getQuestion"); goto poll; }
3165*4b22b933Srs200217 if (!SameDomainName(&q->qname, &pktQuestion.qname))
3166*4b22b933Srs200217 { LogMsg("ERROR: recvSetupResponse - mismatched question in response for llq setup %##s", q->qname.c); goto poll; }
3167*4b22b933Srs200217
3168*4b22b933Srs200217 if (!getLLQAtIndex(m, pktMsg, end, &llq, 0)) { debugf("recvSetupResponse - GetLLQAtIndex"); goto poll; }
3169*4b22b933Srs200217 if (llq.llqOp != kLLQOp_Setup) { LogMsg("ERROR: recvSetupResponse - bad op %d", llq.llqOp); goto poll; }
3170*4b22b933Srs200217 if (llq.vers != kLLQ_Vers) { LogMsg("ERROR: recvSetupResponse - bad vers %d", llq.vers); goto poll; }
3171*4b22b933Srs200217
3172*4b22b933Srs200217 if (info->state == LLQ_InitialRequest) { hndlRequestChallenge(m, pktMsg, end, &llq, q); return; }
3173*4b22b933Srs200217 if (info->state == LLQ_SecondaryRequest) { hndlChallengeResponseAck(m, pktMsg, end, &llq, q); return; }
3174*4b22b933Srs200217 LogMsg("recvSetupResponse - bad state %d", info->state);
3175*4b22b933Srs200217
3176*4b22b933Srs200217 poll:
3177*4b22b933Srs200217 info->state = LLQ_Poll;
3178*4b22b933Srs200217 q->uDNS_info.responseCallback = llqResponseHndlr;
3179*4b22b933Srs200217 info->question->LastQTime = mDNSPlatformTimeNow(m) - (2 * INIT_UCAST_POLL_INTERVAL); // trigger immediate poll
3180*4b22b933Srs200217 info->question->ThisQInterval = INIT_UCAST_POLL_INTERVAL;
3181*4b22b933Srs200217 }
3182*4b22b933Srs200217
startLLQHandshake(mDNS * m,LLQ_Info * info,mDNSBool defer)3183*4b22b933Srs200217 mDNSlocal void startLLQHandshake(mDNS *m, LLQ_Info *info, mDNSBool defer)
3184*4b22b933Srs200217 {
3185*4b22b933Srs200217 DNSMessage msg;
3186*4b22b933Srs200217 mDNSu8 *end;
3187*4b22b933Srs200217 LLQOptData llqData;
3188*4b22b933Srs200217 DNSQuestion *q = info->question;
3189*4b22b933Srs200217 mStatus err = mStatus_NoError;
3190*4b22b933Srs200217 mDNSs32 timenow = mDNSPlatformTimeNow(m);
3191*4b22b933Srs200217 uDNS_GlobalInfo *u = &m->uDNS_info;
3192*4b22b933Srs200217
3193*4b22b933Srs200217 if (IsPrivateV4Addr(&u->AdvertisedV4))
3194*4b22b933Srs200217 {
3195*4b22b933Srs200217 if (!u->LLQNatInfo)
3196*4b22b933Srs200217 {
3197*4b22b933Srs200217 info->state = LLQ_NatMapWait;
3198*4b22b933Srs200217 StartLLQNatMap(m);
3199*4b22b933Srs200217 return;
3200*4b22b933Srs200217 }
3201*4b22b933Srs200217 if (u->LLQNatInfo->state == NATState_Error) goto poll;
3202*4b22b933Srs200217 if (u->LLQNatInfo->state != NATState_Established && u->LLQNatInfo->state != NATState_Legacy)
3203*4b22b933Srs200217 { info->state = LLQ_NatMapWait; info->NATMap = mDNStrue; return; }
3204*4b22b933Srs200217 info->NATMap = mDNStrue; // this llq references the global llq nat mapping
3205*4b22b933Srs200217 }
3206*4b22b933Srs200217
3207*4b22b933Srs200217 if (info->ntries++ >= kLLQ_MAX_TRIES)
3208*4b22b933Srs200217 {
3209*4b22b933Srs200217 debugf("startLLQHandshake: %d failed attempts for LLQ %##s. Polling.", kLLQ_MAX_TRIES, q->qname.c, kLLQ_DEF_RETRY / 60);
3210*4b22b933Srs200217 goto poll;
3211*4b22b933Srs200217 }
3212*4b22b933Srs200217
3213*4b22b933Srs200217 // set llq rdata
3214*4b22b933Srs200217 llqData.vers = kLLQ_Vers;
3215*4b22b933Srs200217 llqData.llqOp = kLLQOp_Setup;
3216*4b22b933Srs200217 llqData.err = LLQErr_NoError;
3217*4b22b933Srs200217 ubzero(llqData.id, 8);
3218*4b22b933Srs200217 llqData.lease = kLLQ_DefLease;
3219*4b22b933Srs200217
3220*4b22b933Srs200217 initializeQuery(&msg, q);
3221*4b22b933Srs200217 end = putLLQ(&msg, msg.data, q, &llqData, mDNStrue);
3222*4b22b933Srs200217 if (!end)
3223*4b22b933Srs200217 {
3224*4b22b933Srs200217 LogMsg("ERROR: startLLQHandshake - putLLQ");
3225*4b22b933Srs200217 info->state = LLQ_Error;
3226*4b22b933Srs200217 return;
3227*4b22b933Srs200217 }
3228*4b22b933Srs200217
3229*4b22b933Srs200217 if (!defer) // if we are to defer, we simply set the retry timers so the request goes out in the future
3230*4b22b933Srs200217 {
3231*4b22b933Srs200217 err = mDNSSendDNSMessage(m, &msg, end, mDNSInterface_Any, &info->servAddr, info->servPort, -1, mDNSNULL);
3232*4b22b933Srs200217 if (err) debugf("ERROR: startLLQHandshake - mDNSSendDNSMessage returned %ld", err);
3233*4b22b933Srs200217 // on error, we procede as normal and retry after the appropriate interval
3234*4b22b933Srs200217 }
3235*4b22b933Srs200217
3236*4b22b933Srs200217 // update question/info state
3237*4b22b933Srs200217 info->state = LLQ_InitialRequest;
3238*4b22b933Srs200217 info->origLease = kLLQ_DefLease;
3239*4b22b933Srs200217 info->retry = timenow + (kLLQ_INIT_RESEND * mDNSPlatformOneSecond);
3240*4b22b933Srs200217 q->LastQTime = timenow;
3241*4b22b933Srs200217 q->uDNS_info.responseCallback = recvSetupResponse;
3242*4b22b933Srs200217 q->uDNS_info.internal = mDNStrue;
3243*4b22b933Srs200217 return;
3244*4b22b933Srs200217
3245*4b22b933Srs200217 poll:
3246*4b22b933Srs200217 info->question->uDNS_info.responseCallback = llqResponseHndlr;
3247*4b22b933Srs200217 info->state = LLQ_Poll;
3248*4b22b933Srs200217 info->question->LastQTime = mDNSPlatformTimeNow(m) - (2 * INIT_UCAST_POLL_INTERVAL); // trigger immediate poll
3249*4b22b933Srs200217 info->question->ThisQInterval = INIT_UCAST_POLL_INTERVAL;
3250*4b22b933Srs200217 }
3251*4b22b933Srs200217
3252*4b22b933Srs200217 // wrapper for startLLQHandshake, invoked by async op callback
startLLQHandshakeCallback(mStatus err,mDNS * const m,void * llqInfo,const AsyncOpResult * result)3253*4b22b933Srs200217 mDNSlocal void startLLQHandshakeCallback(mStatus err, mDNS *const m, void *llqInfo, const AsyncOpResult *result)
3254*4b22b933Srs200217 {
3255*4b22b933Srs200217 LLQ_Info *info = (LLQ_Info *)llqInfo;
3256*4b22b933Srs200217 const zoneData_t *zoneInfo = mDNSNULL;
3257*4b22b933Srs200217
3258*4b22b933Srs200217 // check state first to make sure it is OK to touch question object
3259*4b22b933Srs200217 if (info->state == LLQ_Cancelled)
3260*4b22b933Srs200217 {
3261*4b22b933Srs200217 // StopQuery was called while we were getting the zone info
3262*4b22b933Srs200217 debugf("startLLQHandshake - LLQ Cancelled.");
3263*4b22b933Srs200217 info->question = mDNSNULL; // question may be deallocated
3264*4b22b933Srs200217 ufree(info);
3265*4b22b933Srs200217 return;
3266*4b22b933Srs200217 }
3267*4b22b933Srs200217
3268*4b22b933Srs200217 if (!info->question)
3269*4b22b933Srs200217 { LogMsg("ERROR: startLLQHandshakeCallback invoked with NULL question"); goto error; }
3270*4b22b933Srs200217
3271*4b22b933Srs200217 if (info->state != LLQ_GetZoneInfo)
3272*4b22b933Srs200217 { LogMsg("ERROR: startLLQHandshake - bad state %d", info->state); goto error; }
3273*4b22b933Srs200217
3274*4b22b933Srs200217 if (err)
3275*4b22b933Srs200217 { LogMsg("ERROR: startLLQHandshakeCallback %##s invoked with error code %ld", info->question->qname.c, err); goto poll; }
3276*4b22b933Srs200217
3277*4b22b933Srs200217 if (!result)
3278*4b22b933Srs200217 { LogMsg("ERROR: startLLQHandshakeCallback invoked with NULL result and no error code"); goto error; }
3279*4b22b933Srs200217
3280*4b22b933Srs200217 zoneInfo = &result->zoneData;
3281*4b22b933Srs200217
3282*4b22b933Srs200217 if (!zoneInfo->llqPort.NotAnInteger)
3283*4b22b933Srs200217 { debugf("LLQ port lookup failed - reverting to polling"); info->servPort.NotAnInteger = 0; goto poll; }
3284*4b22b933Srs200217
3285*4b22b933Srs200217 // cache necessary zone data
3286*4b22b933Srs200217 info->servAddr = zoneInfo->primaryAddr;
3287*4b22b933Srs200217 info->servPort = zoneInfo->llqPort;
3288*4b22b933Srs200217 info->ntries = 0;
3289*4b22b933Srs200217
3290*4b22b933Srs200217 if (info->state == LLQ_SuspendDeferred) info->state = LLQ_Suspended;
3291*4b22b933Srs200217 else startLLQHandshake(m, info, mDNSfalse);
3292*4b22b933Srs200217 return;
3293*4b22b933Srs200217
3294*4b22b933Srs200217 poll:
3295*4b22b933Srs200217 info->question->uDNS_info.responseCallback = llqResponseHndlr;
3296*4b22b933Srs200217 info->state = LLQ_Poll;
3297*4b22b933Srs200217 info->question->LastQTime = mDNSPlatformTimeNow(m) - (2 * INIT_UCAST_POLL_INTERVAL); // trigger immediate poll
3298*4b22b933Srs200217 info->question->ThisQInterval = INIT_UCAST_POLL_INTERVAL;
3299*4b22b933Srs200217 return;
3300*4b22b933Srs200217
3301*4b22b933Srs200217 error:
3302*4b22b933Srs200217 info->state = LLQ_Error;
3303*4b22b933Srs200217 }
3304*4b22b933Srs200217
startLLQ(mDNS * m,DNSQuestion * question)3305*4b22b933Srs200217 mDNSlocal mStatus startLLQ(mDNS *m, DNSQuestion *question)
3306*4b22b933Srs200217 {
3307*4b22b933Srs200217 LLQ_Info *info;
3308*4b22b933Srs200217 mStatus err = mStatus_NoError;
3309*4b22b933Srs200217
3310*4b22b933Srs200217 // allocate / init info struct
3311*4b22b933Srs200217 info = umalloc(sizeof(LLQ_Info));
3312*4b22b933Srs200217 if (!info) { LogMsg("ERROR: startLLQ - malloc"); return mStatus_NoMemoryErr; }
3313*4b22b933Srs200217 ubzero(info, sizeof(LLQ_Info));
3314*4b22b933Srs200217 info->state = LLQ_GetZoneInfo;
3315*4b22b933Srs200217
3316*4b22b933Srs200217 // link info/question
3317*4b22b933Srs200217 info->question = question;
3318*4b22b933Srs200217 question->uDNS_info.llq = info;
3319*4b22b933Srs200217
3320*4b22b933Srs200217 question->uDNS_info.responseCallback = llqResponseHndlr;
3321*4b22b933Srs200217
3322*4b22b933Srs200217 err = startGetZoneData(&question->qname, m, mDNSfalse, mDNStrue, startLLQHandshakeCallback, info);
3323*4b22b933Srs200217 if (err)
3324*4b22b933Srs200217 {
3325*4b22b933Srs200217 LogMsg("ERROR: startLLQ - startGetZoneData returned %ld", err);
3326*4b22b933Srs200217 info->question = mDNSNULL;
3327*4b22b933Srs200217 ufree(info);
3328*4b22b933Srs200217 question->uDNS_info.llq = mDNSNULL;
3329*4b22b933Srs200217 return err;
3330*4b22b933Srs200217 }
3331*4b22b933Srs200217
3332*4b22b933Srs200217 LinkActiveQuestion(&m->uDNS_info, question);
3333*4b22b933Srs200217 return err;
3334*4b22b933Srs200217 }
3335*4b22b933Srs200217
recvLLQResponse(mDNS * m,DNSMessage * msg,const mDNSu8 * end,const mDNSAddr * srcaddr,mDNSIPPort srcport,const mDNSInterfaceID InterfaceID)3336*4b22b933Srs200217 mDNSlocal mDNSBool recvLLQResponse(mDNS *m, DNSMessage *msg, const mDNSu8 *end, const mDNSAddr *srcaddr, mDNSIPPort srcport, const mDNSInterfaceID InterfaceID)
3337*4b22b933Srs200217 {
3338*4b22b933Srs200217 DNSQuestion pktQ, *q;
3339*4b22b933Srs200217 uDNS_GlobalInfo *u = &m->uDNS_info;
3340*4b22b933Srs200217 const mDNSu8 *ptr = msg->data;
3341*4b22b933Srs200217 LLQ_Info *llqInfo;
3342*4b22b933Srs200217
3343*4b22b933Srs200217 if (!msg->h.numQuestions) return mDNSfalse;
3344*4b22b933Srs200217
3345*4b22b933Srs200217 ptr = getQuestion(msg, ptr, end, 0, &pktQ);
3346*4b22b933Srs200217 if (!ptr) return mDNSfalse;
3347*4b22b933Srs200217 pktQ.uDNS_info.id = msg->h.id;
3348*4b22b933Srs200217
3349*4b22b933Srs200217 q = u->ActiveQueries;
3350*4b22b933Srs200217 while (q)
3351*4b22b933Srs200217 {
3352*4b22b933Srs200217 llqInfo = q->uDNS_info.llq;
3353*4b22b933Srs200217 if (q->LongLived &&
3354*4b22b933Srs200217 llqInfo &&
3355*4b22b933Srs200217 q->qnamehash == pktQ.qnamehash &&
3356*4b22b933Srs200217 q->qtype == pktQ.qtype &&
3357*4b22b933Srs200217 SameDomainName(&q->qname, &pktQ.qname))
3358*4b22b933Srs200217 {
3359*4b22b933Srs200217 u->CurrentQuery = q;
3360*4b22b933Srs200217 if (llqInfo->state == LLQ_Established || (llqInfo->state == LLQ_Refresh && msg->h.numAnswers))
3361*4b22b933Srs200217 { if (recvLLQEvent(m, q, msg, end, srcaddr, srcport, InterfaceID)) return mDNStrue; }
3362*4b22b933Srs200217 else if (msg->h.id.NotAnInteger == q->uDNS_info.id.NotAnInteger)
3363*4b22b933Srs200217 {
3364*4b22b933Srs200217 if (llqInfo->state == LLQ_Refresh && msg->h.numAdditionals && !msg->h.numAnswers)
3365*4b22b933Srs200217 { recvRefreshReply(m, msg, end, q); return mDNStrue; }
3366*4b22b933Srs200217 if (llqInfo->state < LLQ_Static)
3367*4b22b933Srs200217 {
3368*4b22b933Srs200217 if ((llqInfo->state != LLQ_InitialRequest && llqInfo->state != LLQ_SecondaryRequest) || mDNSSameAddress(srcaddr, &llqInfo->servAddr))
3369*4b22b933Srs200217 { q->uDNS_info.responseCallback(m, msg, end, q, q->uDNS_info.context); return mDNStrue; }
3370*4b22b933Srs200217 }
3371*4b22b933Srs200217 }
3372*4b22b933Srs200217 }
3373*4b22b933Srs200217 q = q->next;
3374*4b22b933Srs200217 }
3375*4b22b933Srs200217 return mDNSfalse;
3376*4b22b933Srs200217 }
3377*4b22b933Srs200217
uDNS_IsActiveQuery(DNSQuestion * const question,uDNS_GlobalInfo * u)3378*4b22b933Srs200217 mDNSexport mDNSBool uDNS_IsActiveQuery(DNSQuestion *const question, uDNS_GlobalInfo *u)
3379*4b22b933Srs200217 {
3380*4b22b933Srs200217 DNSQuestion *q;
3381*4b22b933Srs200217
3382*4b22b933Srs200217 for (q = u->ActiveQueries; q; q = q->next)
3383*4b22b933Srs200217 {
3384*4b22b933Srs200217 if (q == question)
3385*4b22b933Srs200217 {
3386*4b22b933Srs200217 if (!question->uDNS_info.id.NotAnInteger || question->InterfaceID == mDNSInterface_LocalOnly || IsLocalDomain(&question->qname))
3387*4b22b933Srs200217 LogMsg("Warning: Question %##s in Active Unicast Query list with id %d, interfaceID %p",
3388*4b22b933Srs200217 question->qname.c, question->uDNS_info.id.NotAnInteger, question->InterfaceID);
3389*4b22b933Srs200217 return mDNStrue;
3390*4b22b933Srs200217 }
3391*4b22b933Srs200217 }
3392*4b22b933Srs200217 return mDNSfalse;
3393*4b22b933Srs200217 }
3394*4b22b933Srs200217
3395*4b22b933Srs200217 // stopLLQ happens IN ADDITION to stopQuery
stopLLQ(mDNS * m,DNSQuestion * question)3396*4b22b933Srs200217 mDNSlocal void stopLLQ(mDNS *m, DNSQuestion *question)
3397*4b22b933Srs200217 {
3398*4b22b933Srs200217 LLQ_Info *info = question->uDNS_info.llq;
3399*4b22b933Srs200217 (void)m; // unused
3400*4b22b933Srs200217
3401*4b22b933Srs200217 if (!question->LongLived) { LogMsg("ERROR: stopLLQ - LongLived flag not set"); return; }
3402*4b22b933Srs200217 if (!info) { LogMsg("ERROR: stopLLQ - llq info is NULL"); return; }
3403*4b22b933Srs200217
3404*4b22b933Srs200217 switch (info->state)
3405*4b22b933Srs200217 {
3406*4b22b933Srs200217 case LLQ_UnInit:
3407*4b22b933Srs200217 LogMsg("ERROR: stopLLQ - state LLQ_UnInit");
3408*4b22b933Srs200217 //!!!KRS should we unlink info<->question here?
3409*4b22b933Srs200217 return;
3410*4b22b933Srs200217 case LLQ_GetZoneInfo:
3411*4b22b933Srs200217 case LLQ_SuspendDeferred:
3412*4b22b933Srs200217 info->question = mDNSNULL; // remove ref to question, as it may be freed when we get called back from async op
3413*4b22b933Srs200217 info->state = LLQ_Cancelled;
3414*4b22b933Srs200217 return;
3415*4b22b933Srs200217 case LLQ_Established:
3416*4b22b933Srs200217 case LLQ_Refresh:
3417*4b22b933Srs200217 // refresh w/ lease 0
3418*4b22b933Srs200217 sendLLQRefresh(m, question, 0);
3419*4b22b933Srs200217 goto end;
3420*4b22b933Srs200217 default:
3421*4b22b933Srs200217 debugf("stopLLQ - silently discarding LLQ in state %d", info->state);
3422*4b22b933Srs200217 goto end;
3423*4b22b933Srs200217 }
3424*4b22b933Srs200217
3425*4b22b933Srs200217 end:
3426*4b22b933Srs200217 if (info->NATMap) info->NATMap = mDNSfalse;
3427*4b22b933Srs200217 CheckForUnreferencedLLQMapping(m);
3428*4b22b933Srs200217 info->question = mDNSNULL;
3429*4b22b933Srs200217 ufree(info);
3430*4b22b933Srs200217 question->uDNS_info.llq = mDNSNULL;
3431*4b22b933Srs200217 question->LongLived = mDNSfalse;
3432*4b22b933Srs200217 }
3433*4b22b933Srs200217
uDNS_StopQuery(mDNS * const m,DNSQuestion * const question)3434*4b22b933Srs200217 mDNSexport mStatus uDNS_StopQuery(mDNS *const m, DNSQuestion *const question)
3435*4b22b933Srs200217 {
3436*4b22b933Srs200217 uDNS_GlobalInfo *u = &m->uDNS_info;
3437*4b22b933Srs200217 DNSQuestion *qptr, *prev = mDNSNULL;
3438*4b22b933Srs200217 CacheRecord *ka;
3439*4b22b933Srs200217
3440*4b22b933Srs200217 qptr = u->ActiveQueries;
3441*4b22b933Srs200217 while (qptr)
3442*4b22b933Srs200217 {
3443*4b22b933Srs200217 if (qptr == question)
3444*4b22b933Srs200217 {
3445*4b22b933Srs200217 if (question->LongLived && question->uDNS_info.llq)
3446*4b22b933Srs200217 stopLLQ(m, question);
3447*4b22b933Srs200217 if (m->uDNS_info.CurrentQuery == question)
3448*4b22b933Srs200217 m->uDNS_info.CurrentQuery = m->uDNS_info.CurrentQuery->next;
3449*4b22b933Srs200217 while (question->uDNS_info.knownAnswers)
3450*4b22b933Srs200217 {
3451*4b22b933Srs200217 ka = question->uDNS_info.knownAnswers;
3452*4b22b933Srs200217 question->uDNS_info.knownAnswers = question->uDNS_info.knownAnswers->next;
3453*4b22b933Srs200217 ufree(ka);
3454*4b22b933Srs200217 }
3455*4b22b933Srs200217 if (prev) prev->next = question->next;
3456*4b22b933Srs200217 else u->ActiveQueries = question->next;
3457*4b22b933Srs200217 return mStatus_NoError;
3458*4b22b933Srs200217 }
3459*4b22b933Srs200217 prev = qptr;
3460*4b22b933Srs200217 qptr = qptr->next;
3461*4b22b933Srs200217 }
3462*4b22b933Srs200217 LogMsg("uDNS_StopQuery: no such active query (%##s)", question->qname.c);
3463*4b22b933Srs200217 return mStatus_UnknownErr;
3464*4b22b933Srs200217 }
3465*4b22b933Srs200217
startQuery(mDNS * const m,DNSQuestion * const question,mDNSBool internal)3466*4b22b933Srs200217 mDNSlocal mStatus startQuery(mDNS *const m, DNSQuestion *const question, mDNSBool internal)
3467*4b22b933Srs200217 {
3468*4b22b933Srs200217 uDNS_GlobalInfo *u = &m->uDNS_info;
3469*4b22b933Srs200217 //!!!KRS we should check if the question is already in our activequestion list
3470*4b22b933Srs200217 if (!ValidateDomainName(&question->qname))
3471*4b22b933Srs200217 {
3472*4b22b933Srs200217 LogMsg("Attempt to start query with invalid qname %##s (%s)", question->qname.c, DNSTypeName(question->qtype));
3473*4b22b933Srs200217 return mStatus_Invalid;
3474*4b22b933Srs200217 }
3475*4b22b933Srs200217
3476*4b22b933Srs200217 question->next = mDNSNULL;
3477*4b22b933Srs200217 question->qnamehash = DomainNameHashValue(&question->qname); // to do quick domain name comparisons
3478*4b22b933Srs200217 question->uDNS_info.id = newMessageID(u);
3479*4b22b933Srs200217 question->uDNS_info.Answered = mDNSfalse;
3480*4b22b933Srs200217
3481*4b22b933Srs200217 // break here if its and LLQ
3482*4b22b933Srs200217 if (question->LongLived) return startLLQ(m, question);
3483*4b22b933Srs200217
3484*4b22b933Srs200217 question->ThisQInterval = INIT_UCAST_POLL_INTERVAL / 2;
3485*4b22b933Srs200217 question->LastQTime = mDNSPlatformTimeNow(m) - question->ThisQInterval;
3486*4b22b933Srs200217 // store the question/id in active question list
3487*4b22b933Srs200217 question->uDNS_info.internal = internal;
3488*4b22b933Srs200217 LinkActiveQuestion(u, question);
3489*4b22b933Srs200217 question->uDNS_info.knownAnswers = mDNSNULL;
3490*4b22b933Srs200217 LogOperation("uDNS startQuery: %##s (%s)", question->qname.c, DNSTypeName(question->qtype));
3491*4b22b933Srs200217
3492*4b22b933Srs200217 return mStatus_NoError;
3493*4b22b933Srs200217 }
3494*4b22b933Srs200217
uDNS_StartQuery(mDNS * const m,DNSQuestion * const question)3495*4b22b933Srs200217 mDNSexport mStatus uDNS_StartQuery(mDNS *const m, DNSQuestion *const question)
3496*4b22b933Srs200217 {
3497*4b22b933Srs200217 ubzero(&question->uDNS_info, sizeof(uDNS_QuestionInfo));
3498*4b22b933Srs200217 question->uDNS_info.responseCallback = simpleResponseHndlr;
3499*4b22b933Srs200217 question->uDNS_info.context = mDNSNULL;
3500*4b22b933Srs200217 //LogOperation("uDNS_StartQuery %##s (%s)", question->qname.c, DNSTypeName(question->qtype));
3501*4b22b933Srs200217 return startQuery(m, question, 0);
3502*4b22b933Srs200217 }
3503*4b22b933Srs200217
3504*4b22b933Srs200217 // explicitly set response handler
startInternalQuery(DNSQuestion * q,mDNS * m,InternalResponseHndlr callback,void * hndlrContext)3505*4b22b933Srs200217 mDNSlocal mStatus startInternalQuery(DNSQuestion *q, mDNS *m, InternalResponseHndlr callback, void *hndlrContext)
3506*4b22b933Srs200217 {
3507*4b22b933Srs200217 ubzero(&q->uDNS_info, sizeof(uDNS_QuestionInfo));
3508*4b22b933Srs200217 q->QuestionContext = hndlrContext;
3509*4b22b933Srs200217 q->uDNS_info.responseCallback = callback;
3510*4b22b933Srs200217 q->uDNS_info.context = hndlrContext;
3511*4b22b933Srs200217 return startQuery(m, q, 1);
3512*4b22b933Srs200217 }
3513*4b22b933Srs200217
3514*4b22b933Srs200217
3515*4b22b933Srs200217
3516*4b22b933Srs200217 // ***************************************************************************
3517*4b22b933Srs200217 #if COMPILER_LIKES_PRAGMA_MARK
3518*4b22b933Srs200217 #pragma mark - Domain -> Name Server Conversion
3519*4b22b933Srs200217 #endif
3520*4b22b933Srs200217
3521*4b22b933Srs200217
3522*4b22b933Srs200217 /* startGetZoneData
3523*4b22b933Srs200217 *
3524*4b22b933Srs200217 * Asynchronously find the address of the nameserver for the enclosing zone for a given domain name,
3525*4b22b933Srs200217 * i.e. the server to which update and LLQ requests will be sent for a given name. Once the address is
3526*4b22b933Srs200217 * derived, it will be passed to the callback, along with a context pointer. If the zone cannot
3527*4b22b933Srs200217 * be determined or if an error occurs, an all-zeros address will be passed and a message will be
3528*4b22b933Srs200217 * written to the syslog.
3529*4b22b933Srs200217 *
3530*4b22b933Srs200217 * If the FindUpdatePort arg is set, the port on which the server accepts dynamic updates is determined
3531*4b22b933Srs200217 * by querying for the _dns-update._udp.<zone>. SRV record. Likewise, if the FindLLQPort arg is set,
3532*4b22b933Srs200217 * the port on which the server accepts long lived queries is determined by querying for
3533*4b22b933Srs200217 * _dns-llq._udp.<zone>. record. If either of these queries fail, or flags are not specified,
3534*4b22b933Srs200217 * the llqPort and updatePort fields in the result structure are set to zero.
3535*4b22b933Srs200217 *
3536*4b22b933Srs200217 * Steps for deriving the zone name are as follows:
3537*4b22b933Srs200217 *
3538*4b22b933Srs200217 * Query for an SOA record for the required domain. If we don't get an answer (or an SOA in the Authority
3539*4b22b933Srs200217 * section), we strip the leading label from the name and repeat, until we get an answer.
3540*4b22b933Srs200217 *
3541*4b22b933Srs200217 * The name of the SOA record is our enclosing zone. The mname field in the SOA rdata is the domain
3542*4b22b933Srs200217 * name of the primary NS.
3543*4b22b933Srs200217 *
3544*4b22b933Srs200217 * We verify that there is an NS record with this zone for a name and the mname for its rdata.
3545*4b22b933Srs200217 * (!!!KRS this seems redundant, but BIND does this, and it should normally be zero-overhead since
3546*4b22b933Srs200217 * the NS query will get us address records in the additionals section, which we'd otherwise have to
3547*4b22b933Srs200217 * explicitly query for.)
3548*4b22b933Srs200217 *
3549*4b22b933Srs200217 * We then query for the address record for this nameserver (if it is not in the addionals section of
3550*4b22b933Srs200217 * the NS record response.)
3551*4b22b933Srs200217 */
3552*4b22b933Srs200217
3553*4b22b933Srs200217
3554*4b22b933Srs200217 // state machine types and structs
3555*4b22b933Srs200217 //
3556*4b22b933Srs200217
3557*4b22b933Srs200217 // state machine states
3558*4b22b933Srs200217 typedef enum
3559*4b22b933Srs200217 {
3560*4b22b933Srs200217 init,
3561*4b22b933Srs200217 lookupSOA,
3562*4b22b933Srs200217 foundZone,
3563*4b22b933Srs200217 lookupNS,
3564*4b22b933Srs200217 foundNS,
3565*4b22b933Srs200217 lookupA,
3566*4b22b933Srs200217 foundA,
3567*4b22b933Srs200217 lookupPort,
3568*4b22b933Srs200217 foundPort,
3569*4b22b933Srs200217 complete
3570*4b22b933Srs200217 } ntaState;
3571*4b22b933Srs200217
3572*4b22b933Srs200217 // state machine actions
3573*4b22b933Srs200217 typedef enum
3574*4b22b933Srs200217 {
3575*4b22b933Srs200217 smContinue, // continue immediately to next state
3576*4b22b933Srs200217 smBreak, // break until next packet/timeout
3577*4b22b933Srs200217 smError // terminal error - cleanup and abort
3578*4b22b933Srs200217 } smAction;
3579*4b22b933Srs200217
3580*4b22b933Srs200217 typedef struct
3581*4b22b933Srs200217 {
3582*4b22b933Srs200217 domainname origName; // name we originally try to convert
3583*4b22b933Srs200217 domainname *curSOA; // name we have an outstanding SOA query for
3584*4b22b933Srs200217 ntaState state; // determines what we do upon receiving a packet
3585*4b22b933Srs200217 mDNS *m;
3586*4b22b933Srs200217 domainname zone; // left-hand-side of SOA record
3587*4b22b933Srs200217 mDNSu16 zoneClass;
3588*4b22b933Srs200217 domainname ns; // mname in SOA rdata, verified in confirmNS state
3589*4b22b933Srs200217 mDNSv4Addr addr; // address of nameserver
3590*4b22b933Srs200217 DNSQuestion question; // storage for any active question
3591*4b22b933Srs200217 DNSQuestion extraQuestion; // additional storage
3592*4b22b933Srs200217 mDNSBool questionActive; // if true, StopQuery() can be called on the question field
3593*4b22b933Srs200217 mDNSBool findUpdatePort;
3594*4b22b933Srs200217 mDNSBool findLLQPort;
3595*4b22b933Srs200217 mDNSIPPort updatePort;
3596*4b22b933Srs200217 mDNSIPPort llqPort;
3597*4b22b933Srs200217 AsyncOpCallback *callback; // caller specified function to be called upon completion
3598*4b22b933Srs200217 void *callbackInfo;
3599*4b22b933Srs200217 } ntaContext;
3600*4b22b933Srs200217
3601*4b22b933Srs200217
3602*4b22b933Srs200217 // function prototypes (for routines that must be used as fn pointers prior to their definitions,
3603*4b22b933Srs200217 // and allows states to be read top-to-bottom in logical order)
3604*4b22b933Srs200217 mDNSlocal void getZoneData(mDNS *const m, DNSMessage *msg, const mDNSu8 *end, DNSQuestion *question, void *contextPtr);
3605*4b22b933Srs200217 mDNSlocal smAction hndlLookupSOA(DNSMessage *msg, const mDNSu8 *end, ntaContext *context);
3606*4b22b933Srs200217 mDNSlocal void processSOA(ntaContext *context, ResourceRecord *rr);
3607*4b22b933Srs200217 mDNSlocal smAction confirmNS(DNSMessage *msg, const mDNSu8 *end, ntaContext *context);
3608*4b22b933Srs200217 mDNSlocal smAction lookupNSAddr(DNSMessage *msg, const mDNSu8 *end, ntaContext *context);
3609*4b22b933Srs200217 mDNSlocal smAction hndlLookupPorts(DNSMessage *msg, const mDNSu8 *end, ntaContext *context);
3610*4b22b933Srs200217
3611*4b22b933Srs200217 // initialization
startGetZoneData(domainname * name,mDNS * m,mDNSBool findUpdatePort,mDNSBool findLLQPort,AsyncOpCallback callback,void * callbackInfo)3612*4b22b933Srs200217 mDNSlocal mStatus startGetZoneData(domainname *name, mDNS *m, mDNSBool findUpdatePort, mDNSBool findLLQPort,
3613*4b22b933Srs200217 AsyncOpCallback callback, void *callbackInfo)
3614*4b22b933Srs200217 {
3615*4b22b933Srs200217 ntaContext *context = (ntaContext*)umalloc(sizeof(ntaContext));
3616*4b22b933Srs200217 if (!context) { LogMsg("ERROR: startGetZoneData - umalloc failed"); return mStatus_NoMemoryErr; }
3617*4b22b933Srs200217 ubzero(context, sizeof(ntaContext));
3618*4b22b933Srs200217 AssignDomainName(&context->origName, name);
3619*4b22b933Srs200217 context->state = init;
3620*4b22b933Srs200217 context->m = m;
3621*4b22b933Srs200217 context->callback = callback;
3622*4b22b933Srs200217 context->callbackInfo = callbackInfo;
3623*4b22b933Srs200217 context->findUpdatePort = findUpdatePort;
3624*4b22b933Srs200217 context->findLLQPort = findLLQPort;
3625*4b22b933Srs200217 getZoneData(m, mDNSNULL, mDNSNULL, mDNSNULL, context);
3626*4b22b933Srs200217 return mStatus_NoError;
3627*4b22b933Srs200217 }
3628*4b22b933Srs200217
3629*4b22b933Srs200217 // state machine entry routine
getZoneData(mDNS * const m,DNSMessage * msg,const mDNSu8 * end,DNSQuestion * question,void * contextPtr)3630*4b22b933Srs200217 mDNSlocal void getZoneData(mDNS *const m, DNSMessage *msg, const mDNSu8 *end, DNSQuestion *question, void *contextPtr)
3631*4b22b933Srs200217 {
3632*4b22b933Srs200217 AsyncOpResult result;
3633*4b22b933Srs200217 ntaContext *context = (ntaContext*)contextPtr;
3634*4b22b933Srs200217 smAction action;
3635*4b22b933Srs200217
3636*4b22b933Srs200217 // unused
3637*4b22b933Srs200217 (void)m;
3638*4b22b933Srs200217 (void)question;
3639*4b22b933Srs200217
3640*4b22b933Srs200217 // stop any active question
3641*4b22b933Srs200217 if (context->questionActive)
3642*4b22b933Srs200217 {
3643*4b22b933Srs200217 uDNS_StopQuery(context->m, &context->question);
3644*4b22b933Srs200217 context->questionActive = mDNSfalse;
3645*4b22b933Srs200217 }
3646*4b22b933Srs200217
3647*4b22b933Srs200217 if (msg && msg->h.flags.b[2] >> 4 && msg->h.flags.b[2] >> 4 != kDNSFlag1_RC_NXDomain)
3648*4b22b933Srs200217 {
3649*4b22b933Srs200217 // rcode non-zero, non-nxdomain
3650*4b22b933Srs200217 LogMsg("ERROR: getZoneData - received response w/ rcode %d", msg->h.flags.b[2] >> 4);
3651*4b22b933Srs200217 goto error;
3652*4b22b933Srs200217 }
3653*4b22b933Srs200217
3654*4b22b933Srs200217 switch (context->state)
3655*4b22b933Srs200217 {
3656*4b22b933Srs200217 case init:
3657*4b22b933Srs200217 case lookupSOA:
3658*4b22b933Srs200217 action = hndlLookupSOA(msg, end, context);
3659*4b22b933Srs200217 if (action == smError) goto error;
3660*4b22b933Srs200217 if (action == smBreak) return;
3661*4b22b933Srs200217 case foundZone:
3662*4b22b933Srs200217 case lookupNS:
3663*4b22b933Srs200217 action = confirmNS(msg, end, context);
3664*4b22b933Srs200217 if (action == smError) goto error;
3665*4b22b933Srs200217 if (action == smBreak) return;
3666*4b22b933Srs200217 case foundNS:
3667*4b22b933Srs200217 case lookupA:
3668*4b22b933Srs200217 action = lookupNSAddr(msg, end, context);
3669*4b22b933Srs200217 if (action == smError) goto error;
3670*4b22b933Srs200217 if (action == smBreak) return;
3671*4b22b933Srs200217 case foundA:
3672*4b22b933Srs200217 if (!context->findUpdatePort && !context->findLLQPort)
3673*4b22b933Srs200217 {
3674*4b22b933Srs200217 context->state = complete;
3675*4b22b933Srs200217 break;
3676*4b22b933Srs200217 }
3677*4b22b933Srs200217 case lookupPort:
3678*4b22b933Srs200217 action = hndlLookupPorts(msg, end, context);
3679*4b22b933Srs200217 if (action == smError) goto error;
3680*4b22b933Srs200217 if (action == smBreak) return;
3681*4b22b933Srs200217 if (action == smContinue) context->state = complete;
3682*4b22b933Srs200217 case foundPort:
3683*4b22b933Srs200217 case complete: break;
3684*4b22b933Srs200217 }
3685*4b22b933Srs200217
3686*4b22b933Srs200217 if (context->state != complete)
3687*4b22b933Srs200217 {
3688*4b22b933Srs200217 LogMsg("ERROR: getZoneData - exited state machine with state %d", context->state);
3689*4b22b933Srs200217 goto error;
3690*4b22b933Srs200217 }
3691*4b22b933Srs200217
3692*4b22b933Srs200217 result.type = zoneDataResult;
3693*4b22b933Srs200217 result.zoneData.primaryAddr.ip.v4 = context->addr;
3694*4b22b933Srs200217 result.zoneData.primaryAddr.type = mDNSAddrType_IPv4;
3695*4b22b933Srs200217 AssignDomainName(&result.zoneData.zoneName, &context->zone);
3696*4b22b933Srs200217 result.zoneData.zoneClass = context->zoneClass;
3697*4b22b933Srs200217
3698*4b22b933Srs200217 if (context->findLLQPort)
3699*4b22b933Srs200217 result.zoneData.llqPort = context->llqPort;
3700*4b22b933Srs200217 else
3701*4b22b933Srs200217 result.zoneData.llqPort = zeroIPPort;
3702*4b22b933Srs200217
3703*4b22b933Srs200217 if (context->findUpdatePort)
3704*4b22b933Srs200217 result.zoneData.updatePort = context->updatePort;
3705*4b22b933Srs200217 else
3706*4b22b933Srs200217 result.zoneData.updatePort = zeroIPPort;
3707*4b22b933Srs200217
3708*4b22b933Srs200217 context->callback(mStatus_NoError, context->m, context->callbackInfo, &result);
3709*4b22b933Srs200217 goto cleanup;
3710*4b22b933Srs200217
3711*4b22b933Srs200217 error:
3712*4b22b933Srs200217 if (context && context->callback)
3713*4b22b933Srs200217 context->callback(mStatus_UnknownErr, context->m, context->callbackInfo, mDNSNULL);
3714*4b22b933Srs200217 cleanup:
3715*4b22b933Srs200217 if (context && context->questionActive)
3716*4b22b933Srs200217 {
3717*4b22b933Srs200217 uDNS_StopQuery(context->m, &context->question);
3718*4b22b933Srs200217 context->questionActive = mDNSfalse;
3719*4b22b933Srs200217 }
3720*4b22b933Srs200217 if (context) ufree(context);
3721*4b22b933Srs200217 }
3722*4b22b933Srs200217
hndlLookupSOA(DNSMessage * msg,const mDNSu8 * end,ntaContext * context)3723*4b22b933Srs200217 mDNSlocal smAction hndlLookupSOA(DNSMessage *msg, const mDNSu8 *end, ntaContext *context)
3724*4b22b933Srs200217 {
3725*4b22b933Srs200217 mStatus err;
3726*4b22b933Srs200217 LargeCacheRecord lcr;
3727*4b22b933Srs200217 ResourceRecord *rr = &lcr.r.resrec;
3728*4b22b933Srs200217 DNSQuestion *query = &context->question;
3729*4b22b933Srs200217 const mDNSu8 *ptr;
3730*4b22b933Srs200217
3731*4b22b933Srs200217 if (msg)
3732*4b22b933Srs200217 {
3733*4b22b933Srs200217 // if msg contains SOA record in answer or authority sections, update context/state and return
3734*4b22b933Srs200217 int i;
3735*4b22b933Srs200217 ptr = LocateAnswers(msg, end);
3736*4b22b933Srs200217 for (i = 0; i < msg->h.numAnswers; i++)
3737*4b22b933Srs200217 {
3738*4b22b933Srs200217 ptr = GetLargeResourceRecord(context->m, msg, ptr, end, 0, kDNSRecordTypePacketAns, &lcr);
3739*4b22b933Srs200217 if (!ptr) { LogMsg("ERROR: hndlLookupSOA, Answers - GetLargeResourceRecord returned NULL"); return smError; }
3740*4b22b933Srs200217 if (rr->rrtype == kDNSType_SOA && SameDomainName(context->curSOA, rr->name))
3741*4b22b933Srs200217 {
3742*4b22b933Srs200217 processSOA(context, rr);
3743*4b22b933Srs200217 return smContinue;
3744*4b22b933Srs200217 }
3745*4b22b933Srs200217 }
3746*4b22b933Srs200217 ptr = LocateAuthorities(msg, end);
3747*4b22b933Srs200217 // SOA not in answers, check in authority
3748*4b22b933Srs200217 for (i = 0; i < msg->h.numAuthorities; i++)
3749*4b22b933Srs200217 {
3750*4b22b933Srs200217 ptr = GetLargeResourceRecord(context->m, msg, ptr, end, 0, kDNSRecordTypePacketAns, &lcr); ///!!!KRS using type PacketAns for auth
3751*4b22b933Srs200217 if (!ptr) { LogMsg("ERROR: hndlLookupSOA, Authority - GetLargeResourceRecord returned NULL"); return smError; }
3752*4b22b933Srs200217 if (rr->rrtype == kDNSType_SOA)
3753*4b22b933Srs200217 {
3754*4b22b933Srs200217 processSOA(context, rr);
3755*4b22b933Srs200217 return smContinue;
3756*4b22b933Srs200217 }
3757*4b22b933Srs200217 }
3758*4b22b933Srs200217 }
3759*4b22b933Srs200217
3760*4b22b933Srs200217 if (context->state != init && !context->curSOA->c[0])
3761*4b22b933Srs200217 {
3762*4b22b933Srs200217 // we've gone down to the root and have not found an SOA
3763*4b22b933Srs200217 LogMsg("ERROR: hndlLookupSOA - recursed to root label of %##s without finding SOA",
3764*4b22b933Srs200217 context->origName.c);
3765*4b22b933Srs200217 return smError;
3766*4b22b933Srs200217 }
3767*4b22b933Srs200217
3768*4b22b933Srs200217 ubzero(query, sizeof(DNSQuestion));
3769*4b22b933Srs200217 // chop off leading label unless this is our first try
3770*4b22b933Srs200217 if (context->state == init) context->curSOA = &context->origName;
3771*4b22b933Srs200217 else context->curSOA = (domainname *)(context->curSOA->c + context->curSOA->c[0]+1);
3772*4b22b933Srs200217
3773*4b22b933Srs200217 context->state = lookupSOA;
3774*4b22b933Srs200217 AssignDomainName(&query->qname, context->curSOA);
3775*4b22b933Srs200217 query->qtype = kDNSType_SOA;
3776*4b22b933Srs200217 query->qclass = kDNSClass_IN;
3777*4b22b933Srs200217 err = startInternalQuery(query, context->m, getZoneData, context);
3778*4b22b933Srs200217 context->questionActive = mDNStrue;
3779*4b22b933Srs200217 if (err) LogMsg("hndlLookupSOA: startInternalQuery returned error %ld (breaking until next periodic retransmission)", err);
3780*4b22b933Srs200217
3781*4b22b933Srs200217 return smBreak; // break from state machine until we receive another packet
3782*4b22b933Srs200217 }
3783*4b22b933Srs200217
processSOA(ntaContext * context,ResourceRecord * rr)3784*4b22b933Srs200217 mDNSlocal void processSOA(ntaContext *context, ResourceRecord *rr)
3785*4b22b933Srs200217 {
3786*4b22b933Srs200217 AssignDomainName(&context->zone, rr->name);
3787*4b22b933Srs200217 context->zoneClass = rr->rrclass;
3788*4b22b933Srs200217 AssignDomainName(&context->ns, &rr->rdata->u.soa.mname);
3789*4b22b933Srs200217 context->state = foundZone;
3790*4b22b933Srs200217 }
3791*4b22b933Srs200217
3792*4b22b933Srs200217
confirmNS(DNSMessage * msg,const mDNSu8 * end,ntaContext * context)3793*4b22b933Srs200217 mDNSlocal smAction confirmNS(DNSMessage *msg, const mDNSu8 *end, ntaContext *context)
3794*4b22b933Srs200217 {
3795*4b22b933Srs200217 DNSQuestion *query = &context->question;
3796*4b22b933Srs200217 mStatus err;
3797*4b22b933Srs200217 LargeCacheRecord lcr;
3798*4b22b933Srs200217 const ResourceRecord *const rr = &lcr.r.resrec;
3799*4b22b933Srs200217 const mDNSu8 *ptr;
3800*4b22b933Srs200217 int i;
3801*4b22b933Srs200217
3802*4b22b933Srs200217 if (context->state == foundZone)
3803*4b22b933Srs200217 {
3804*4b22b933Srs200217 // we've just learned the zone. confirm that an NS record exists
3805*4b22b933Srs200217 AssignDomainName(&query->qname, &context->zone);
3806*4b22b933Srs200217 query->qtype = kDNSType_NS;
3807*4b22b933Srs200217 query->qclass = kDNSClass_IN;
3808*4b22b933Srs200217 err = startInternalQuery(query, context->m, getZoneData, context);
3809*4b22b933Srs200217 context->questionActive = mDNStrue;
3810*4b22b933Srs200217 if (err) LogMsg("confirmNS: startInternalQuery returned error %ld (breaking until next periodic retransmission", err);
3811*4b22b933Srs200217 context->state = lookupNS;
3812*4b22b933Srs200217 return smBreak; // break from SM until we receive another packet
3813*4b22b933Srs200217 }
3814*4b22b933Srs200217 else if (context->state == lookupNS)
3815*4b22b933Srs200217 {
3816*4b22b933Srs200217 ptr = LocateAnswers(msg, end);
3817*4b22b933Srs200217 for (i = 0; i < msg->h.numAnswers; i++)
3818*4b22b933Srs200217 {
3819*4b22b933Srs200217 ptr = GetLargeResourceRecord(context->m, msg, ptr, end, 0, kDNSRecordTypePacketAns, &lcr);
3820*4b22b933Srs200217 if (!ptr) { LogMsg("ERROR: confirmNS, Answers - GetLargeResourceRecord returned NULL"); return smError; }
3821*4b22b933Srs200217 if (rr->rrtype == kDNSType_NS &&
3822*4b22b933Srs200217 SameDomainName(&context->zone, rr->name) && SameDomainName(&context->ns, &rr->rdata->u.name))
3823*4b22b933Srs200217 {
3824*4b22b933Srs200217 context->state = foundNS;
3825*4b22b933Srs200217 return smContinue; // next routine will examine additionals section of A record
3826*4b22b933Srs200217 }
3827*4b22b933Srs200217 }
3828*4b22b933Srs200217 debugf("ERROR: could not confirm existence of record %##s NS %##s", context->zone.c, context->ns.c);
3829*4b22b933Srs200217 return smError;
3830*4b22b933Srs200217 }
3831*4b22b933Srs200217 else { LogMsg("ERROR: confirmNS - bad state %d", context->state); return smError; }
3832*4b22b933Srs200217 }
3833*4b22b933Srs200217
queryNSAddr(ntaContext * context)3834*4b22b933Srs200217 mDNSlocal smAction queryNSAddr(ntaContext *context)
3835*4b22b933Srs200217 {
3836*4b22b933Srs200217 mStatus err;
3837*4b22b933Srs200217 DNSQuestion *query = &context->question;
3838*4b22b933Srs200217
3839*4b22b933Srs200217 AssignDomainName(&query->qname, &context->ns);
3840*4b22b933Srs200217 query->qtype = kDNSType_A;
3841*4b22b933Srs200217 query->qclass = kDNSClass_IN;
3842*4b22b933Srs200217 err = startInternalQuery(query, context->m, getZoneData, context);
3843*4b22b933Srs200217 context->questionActive = mDNStrue;
3844*4b22b933Srs200217 if (err) LogMsg("confirmNS: startInternalQuery returned error %ld (breaking until next periodic retransmission)", err);
3845*4b22b933Srs200217 context->state = lookupA;
3846*4b22b933Srs200217 return smBreak;
3847*4b22b933Srs200217 }
3848*4b22b933Srs200217
lookupNSAddr(DNSMessage * msg,const mDNSu8 * end,ntaContext * context)3849*4b22b933Srs200217 mDNSlocal smAction lookupNSAddr(DNSMessage *msg, const mDNSu8 *end, ntaContext *context)
3850*4b22b933Srs200217 {
3851*4b22b933Srs200217 const mDNSu8 *ptr;
3852*4b22b933Srs200217 int i;
3853*4b22b933Srs200217 LargeCacheRecord lcr;
3854*4b22b933Srs200217 ResourceRecord *rr = &lcr.r.resrec;
3855*4b22b933Srs200217
3856*4b22b933Srs200217 if (context->state == foundNS)
3857*4b22b933Srs200217 {
3858*4b22b933Srs200217 // we just found the NS record - look for the corresponding A record in the Additionals section
3859*4b22b933Srs200217 if (!msg->h.numAdditionals) return queryNSAddr(context);
3860*4b22b933Srs200217 ptr = LocateAdditionals(msg, end);
3861*4b22b933Srs200217 if (!ptr)
3862*4b22b933Srs200217 {
3863*4b22b933Srs200217 LogMsg("ERROR: lookupNSAddr - LocateAdditionals returned NULL, expected %d additionals", msg->h.numAdditionals);
3864*4b22b933Srs200217 return queryNSAddr(context);
3865*4b22b933Srs200217 }
3866*4b22b933Srs200217 else
3867*4b22b933Srs200217 {
3868*4b22b933Srs200217 for (i = 0; i < msg->h.numAdditionals; i++)
3869*4b22b933Srs200217 {
3870*4b22b933Srs200217 ptr = GetLargeResourceRecord(context->m, msg, ptr, end, 0, kDNSRecordTypePacketAns, &lcr);
3871*4b22b933Srs200217 if (!ptr)
3872*4b22b933Srs200217 {
3873*4b22b933Srs200217 LogMsg("ERROR: lookupNSAddr, Additionals - GetLargeResourceRecord returned NULL");
3874*4b22b933Srs200217 return queryNSAddr(context);
3875*4b22b933Srs200217 }
3876*4b22b933Srs200217 if (rr->rrtype == kDNSType_A && SameDomainName(&context->ns, rr->name))
3877*4b22b933Srs200217 {
3878*4b22b933Srs200217 context->addr = rr->rdata->u.ipv4;
3879*4b22b933Srs200217 context->state = foundA;
3880*4b22b933Srs200217 return smContinue;
3881*4b22b933Srs200217 }
3882*4b22b933Srs200217 }
3883*4b22b933Srs200217 }
3884*4b22b933Srs200217 // no A record in Additionals - query the server
3885*4b22b933Srs200217 return queryNSAddr(context);
3886*4b22b933Srs200217 }
3887*4b22b933Srs200217 else if (context->state == lookupA)
3888*4b22b933Srs200217 {
3889*4b22b933Srs200217 ptr = LocateAnswers(msg, end);
3890*4b22b933Srs200217 if (!ptr) { LogMsg("ERROR: lookupNSAddr: LocateAnswers returned NULL"); return smError; }
3891*4b22b933Srs200217 for (i = 0; i < msg->h.numAnswers; i++)
3892*4b22b933Srs200217 {
3893*4b22b933Srs200217 ptr = GetLargeResourceRecord(context->m, msg, ptr, end, 0, kDNSRecordTypePacketAns, &lcr);
3894*4b22b933Srs200217 if (!ptr) { LogMsg("ERROR: lookupNSAddr, Answers - GetLargeResourceRecord returned NULL"); break; }
3895*4b22b933Srs200217 if (rr->rrtype == kDNSType_A && SameDomainName(&context->ns, rr->name))
3896*4b22b933Srs200217 {
3897*4b22b933Srs200217 context->addr = rr->rdata->u.ipv4;
3898*4b22b933Srs200217 context->state = foundA;
3899*4b22b933Srs200217 return smContinue;
3900*4b22b933Srs200217 }
3901*4b22b933Srs200217 }
3902*4b22b933Srs200217 LogMsg("ERROR: lookupNSAddr: Address record not found in answer section");
3903*4b22b933Srs200217 return smError;
3904*4b22b933Srs200217 }
3905*4b22b933Srs200217 else { LogMsg("ERROR: lookupNSAddr - bad state %d", context->state); return smError; }
3906*4b22b933Srs200217 }
3907*4b22b933Srs200217
lookupDNSPort(DNSMessage * msg,const mDNSu8 * end,ntaContext * context,char * portName,mDNSIPPort * port)3908*4b22b933Srs200217 mDNSlocal smAction lookupDNSPort(DNSMessage *msg, const mDNSu8 *end, ntaContext *context, char *portName, mDNSIPPort *port)
3909*4b22b933Srs200217 {
3910*4b22b933Srs200217 int i;
3911*4b22b933Srs200217 LargeCacheRecord lcr;
3912*4b22b933Srs200217 const mDNSu8 *ptr;
3913*4b22b933Srs200217 DNSQuestion *q;
3914*4b22b933Srs200217 mStatus err;
3915*4b22b933Srs200217
3916*4b22b933Srs200217 if (context->state == lookupPort) // we've already issued the query
3917*4b22b933Srs200217 {
3918*4b22b933Srs200217 if (!msg) { LogMsg("ERROR: hndlLookupUpdatePort - NULL message"); return smError; }
3919*4b22b933Srs200217 ptr = LocateAnswers(msg, end);
3920*4b22b933Srs200217 for (i = 0; i < msg->h.numAnswers; i++)
3921*4b22b933Srs200217 {
3922*4b22b933Srs200217 ptr = GetLargeResourceRecord(context->m, msg, ptr, end, 0, kDNSRecordTypePacketAns, &lcr);
3923*4b22b933Srs200217 if (!ptr) { LogMsg("ERROR: hndlLookupUpdatePort - GetLargeResourceRecord returned NULL"); return smError; }
3924*4b22b933Srs200217 if (ResourceRecordAnswersQuestion(&lcr.r.resrec, &context->question))
3925*4b22b933Srs200217 {
3926*4b22b933Srs200217 *port = lcr.r.resrec.rdata->u.srv.port;
3927*4b22b933Srs200217 context->state = foundPort;
3928*4b22b933Srs200217 return smContinue;
3929*4b22b933Srs200217 }
3930*4b22b933Srs200217 }
3931*4b22b933Srs200217 debugf("hndlLookupUpdatePort - no answer for type %s", portName);
3932*4b22b933Srs200217 port->NotAnInteger = 0;
3933*4b22b933Srs200217 context->state = foundPort;
3934*4b22b933Srs200217 return smContinue;
3935*4b22b933Srs200217 }
3936*4b22b933Srs200217
3937*4b22b933Srs200217 // query the server for the update port for the zone
3938*4b22b933Srs200217 context->state = lookupPort;
3939*4b22b933Srs200217 q = &context->question;
3940*4b22b933Srs200217 MakeDomainNameFromDNSNameString(&q->qname, portName);
3941*4b22b933Srs200217 AppendDomainName(&q->qname, &context->zone);
3942*4b22b933Srs200217 q->qtype = kDNSType_SRV;
3943*4b22b933Srs200217 q->qclass = kDNSClass_IN;
3944*4b22b933Srs200217 err = startInternalQuery(q, context->m, getZoneData, context);
3945*4b22b933Srs200217 context->questionActive = mDNStrue;
3946*4b22b933Srs200217 if (err) LogMsg("hndlLookupSOA: startInternalQuery returned error %ld (breaking until next periodic retransmission)", err);
3947*4b22b933Srs200217 return smBreak; // break from state machine until we receive another packet
3948*4b22b933Srs200217 }
3949*4b22b933Srs200217
hndlLookupPorts(DNSMessage * msg,const mDNSu8 * end,ntaContext * context)3950*4b22b933Srs200217 mDNSlocal smAction hndlLookupPorts(DNSMessage *msg, const mDNSu8 *end, ntaContext *context)
3951*4b22b933Srs200217 {
3952*4b22b933Srs200217 smAction action;
3953*4b22b933Srs200217
3954*4b22b933Srs200217 if (context->findUpdatePort && !context->updatePort.NotAnInteger)
3955*4b22b933Srs200217 {
3956*4b22b933Srs200217 action = lookupDNSPort(msg, end, context, UPDATE_PORT_NAME, &context->updatePort);
3957*4b22b933Srs200217 if (action != smContinue) return action;
3958*4b22b933Srs200217 }
3959*4b22b933Srs200217 if (context->findLLQPort && !context->llqPort.NotAnInteger)
3960*4b22b933Srs200217 return lookupDNSPort(msg, end, context, LLQ_PORT_NAME, &context->llqPort);
3961*4b22b933Srs200217
3962*4b22b933Srs200217 return smContinue;
3963*4b22b933Srs200217 }
3964*4b22b933Srs200217
3965*4b22b933Srs200217
3966*4b22b933Srs200217 // ***************************************************************************
3967*4b22b933Srs200217 #if COMPILER_LIKES_PRAGMA_MARK
3968*4b22b933Srs200217 #pragma mark - Truncation Handling
3969*4b22b933Srs200217 #endif
3970*4b22b933Srs200217
3971*4b22b933Srs200217 typedef struct
3972*4b22b933Srs200217 {
3973*4b22b933Srs200217 DNSQuestion *question;
3974*4b22b933Srs200217 DNSMessage *reply;
3975*4b22b933Srs200217 mDNSu16 replylen;
3976*4b22b933Srs200217 int nread;
3977*4b22b933Srs200217 mDNS *m;
3978*4b22b933Srs200217 } tcpInfo_t;
3979*4b22b933Srs200217
3980*4b22b933Srs200217 // issue queries over a conected socket
conQueryCallback(int sd,void * context,mDNSBool ConnectionEstablished)3981*4b22b933Srs200217 mDNSlocal void conQueryCallback(int sd, void *context, mDNSBool ConnectionEstablished)
3982*4b22b933Srs200217 {
3983*4b22b933Srs200217 mStatus err = 0;
3984*4b22b933Srs200217 char msgbuf[356]; // 96 (hdr) + 256 (domain) + 4 (class/type)
3985*4b22b933Srs200217 DNSMessage *msg;
3986*4b22b933Srs200217 mDNSu8 *end;
3987*4b22b933Srs200217 tcpInfo_t *info = (tcpInfo_t *)context;
3988*4b22b933Srs200217 DNSQuestion *question = info->question;
3989*4b22b933Srs200217 int n;
3990*4b22b933Srs200217 mDNS *m = info->m;
3991*4b22b933Srs200217
3992*4b22b933Srs200217 mDNS_Lock(m);
3993*4b22b933Srs200217
3994*4b22b933Srs200217 if (ConnectionEstablished)
3995*4b22b933Srs200217 {
3996*4b22b933Srs200217 // connection is established - send the message
3997*4b22b933Srs200217 msg = (DNSMessage *)&msgbuf;
3998*4b22b933Srs200217 err = constructQueryMsg(msg, &end, question);
3999*4b22b933Srs200217 if (err) { LogMsg("ERROR: conQueryCallback: constructQueryMsg - %ld", err); goto error; }
4000*4b22b933Srs200217 err = mDNSSendDNSMessage(m, msg, end, mDNSInterface_Any, &zeroAddr, zeroIPPort, sd, mDNSNULL);
4001*4b22b933Srs200217 question->LastQTime = mDNSPlatformTimeNow(m);
4002*4b22b933Srs200217 if (err) { debugf("ERROR: conQueryCallback: mDNSSendDNSMessage_tcp - %ld", err); goto error; }
4003*4b22b933Srs200217 }
4004*4b22b933Srs200217 else
4005*4b22b933Srs200217 {
4006*4b22b933Srs200217 if (!info->nread)
4007*4b22b933Srs200217 {
4008*4b22b933Srs200217 // read msg len
4009*4b22b933Srs200217 mDNSu8 lenbuf[2];
4010*4b22b933Srs200217 n = mDNSPlatformReadTCP(sd, lenbuf, 2);
4011*4b22b933Srs200217 if (n != 2)
4012*4b22b933Srs200217 {
4013*4b22b933Srs200217 LogMsg("ERROR:conQueryCallback - attempt to read message length failed (read returned %d)", n);
4014*4b22b933Srs200217 goto error;
4015*4b22b933Srs200217 }
4016*4b22b933Srs200217 info->replylen = (mDNSu16)((mDNSu16)lenbuf[0] << 8 | lenbuf[1]);
4017*4b22b933Srs200217 if (info->replylen < sizeof(DNSMessageHeader))
4018*4b22b933Srs200217 { LogMsg("ERROR: conQueryCallback - length too short (%d bytes)", info->replylen); goto error; }
4019*4b22b933Srs200217 info->reply = umalloc(info->replylen);
4020*4b22b933Srs200217 if (!info->reply) { LogMsg("ERROR: conQueryCallback - malloc failed"); goto error; }
4021*4b22b933Srs200217 }
4022*4b22b933Srs200217 n = mDNSPlatformReadTCP(sd, ((char *)info->reply) + info->nread, info->replylen - info->nread);
4023*4b22b933Srs200217 if (n < 0) { LogMsg("ERROR: conQueryCallback - read returned %d", n); goto error; }
4024*4b22b933Srs200217 info->nread += n;
4025*4b22b933Srs200217 if (info->nread == info->replylen)
4026*4b22b933Srs200217 {
4027*4b22b933Srs200217 // Finished reading message; convert the integer parts which are in IETF byte-order (MSB first, LSB second)
4028*4b22b933Srs200217 DNSMessage *msg = info->reply;
4029*4b22b933Srs200217 mDNSu8 *ptr = (mDNSu8 *)&msg->h.numQuestions;
4030*4b22b933Srs200217 msg->h.numQuestions = (mDNSu16)((mDNSu16)ptr[0] << 8 | ptr[1]);
4031*4b22b933Srs200217 msg->h.numAnswers = (mDNSu16)((mDNSu16)ptr[2] << 8 | ptr[3]);
4032*4b22b933Srs200217 msg->h.numAuthorities = (mDNSu16)((mDNSu16)ptr[4] << 8 | ptr[5]);
4033*4b22b933Srs200217 msg->h.numAdditionals = (mDNSu16)((mDNSu16)ptr[6] << 8 | ptr[7]);
4034*4b22b933Srs200217 uDNS_ReceiveMsg(m, msg, (mDNSu8 *)msg + info->replylen, mDNSNULL, zeroIPPort, mDNSNULL, zeroIPPort, question->InterfaceID);
4035*4b22b933Srs200217 mDNSPlatformTCPCloseConnection(sd);
4036*4b22b933Srs200217 ufree(info->reply);
4037*4b22b933Srs200217 ufree(info);
4038*4b22b933Srs200217 }
4039*4b22b933Srs200217 }
4040*4b22b933Srs200217
4041*4b22b933Srs200217 mDNS_Unlock(m);
4042*4b22b933Srs200217 return;
4043*4b22b933Srs200217
4044*4b22b933Srs200217 error:
4045*4b22b933Srs200217 mDNSPlatformTCPCloseConnection(sd);
4046*4b22b933Srs200217 if (info->reply) ufree(info->reply);
4047*4b22b933Srs200217 ufree(info);
4048*4b22b933Srs200217 mDNS_Unlock(m);
4049*4b22b933Srs200217 }
4050*4b22b933Srs200217
hndlTruncatedAnswer(DNSQuestion * question,const mDNSAddr * src,mDNS * m)4051*4b22b933Srs200217 mDNSlocal void hndlTruncatedAnswer(DNSQuestion *question, const mDNSAddr *src, mDNS *m)
4052*4b22b933Srs200217 {
4053*4b22b933Srs200217 mStatus connectionStatus;
4054*4b22b933Srs200217 uDNS_QuestionInfo *info = &question->uDNS_info;
4055*4b22b933Srs200217 int sd;
4056*4b22b933Srs200217 tcpInfo_t *context;
4057*4b22b933Srs200217
4058*4b22b933Srs200217 if (!src) { LogMsg("hndlTruncatedAnswer: TCP DNS response had TC bit set: ignoring"); return; }
4059*4b22b933Srs200217
4060*4b22b933Srs200217 context = (tcpInfo_t *)umalloc(sizeof(tcpInfo_t));
4061*4b22b933Srs200217 if (!context) { LogMsg("ERROR: hndlTruncatedAnswer - memallocate failed"); return; }
4062*4b22b933Srs200217 ubzero(context, sizeof(tcpInfo_t));
4063*4b22b933Srs200217 context->question = question;
4064*4b22b933Srs200217 context->m = m;
4065*4b22b933Srs200217 info->id = newMessageID(&m->uDNS_info);
4066*4b22b933Srs200217
4067*4b22b933Srs200217 connectionStatus = mDNSPlatformTCPConnect(src, UnicastDNSPort, question->InterfaceID, conQueryCallback, context, &sd);
4068*4b22b933Srs200217 if (connectionStatus == mStatus_ConnEstablished) // manually invoke callback if connection completes
4069*4b22b933Srs200217 {
4070*4b22b933Srs200217 conQueryCallback(sd, context, mDNStrue);
4071*4b22b933Srs200217 return;
4072*4b22b933Srs200217 }
4073*4b22b933Srs200217 if (connectionStatus == mStatus_ConnPending) return; // callback will be automatically invoked when connection completes
4074*4b22b933Srs200217 LogMsg("hndlTruncatedAnswer: connection failed");
4075*4b22b933Srs200217 uDNS_StopQuery(m, question); //!!!KRS can we really call this here?
4076*4b22b933Srs200217 }
4077*4b22b933Srs200217
4078*4b22b933Srs200217
4079*4b22b933Srs200217 // ***************************************************************************
4080*4b22b933Srs200217 #if COMPILER_LIKES_PRAGMA_MARK
4081*4b22b933Srs200217 #pragma mark - Dynamic Updates
4082*4b22b933Srs200217 #endif
4083*4b22b933Srs200217
sendRecordRegistration(mDNS * const m,AuthRecord * rr)4084*4b22b933Srs200217 mDNSlocal void sendRecordRegistration(mDNS *const m, AuthRecord *rr)
4085*4b22b933Srs200217 {
4086*4b22b933Srs200217 DNSMessage msg;
4087*4b22b933Srs200217 mDNSu8 *ptr = msg.data;
4088*4b22b933Srs200217 mDNSu8 *end = (mDNSu8 *)&msg + sizeof(DNSMessage);
4089*4b22b933Srs200217 uDNS_GlobalInfo *u = &m->uDNS_info;
4090*4b22b933Srs200217 mDNSOpaque16 id;
4091*4b22b933Srs200217 uDNS_RegInfo *regInfo = &rr->uDNS_info;
4092*4b22b933Srs200217 mStatus err = mStatus_UnknownErr;
4093*4b22b933Srs200217
4094*4b22b933Srs200217 id = newMessageID(u);
4095*4b22b933Srs200217 InitializeDNSMessage(&msg.h, id, UpdateReqFlags);
4096*4b22b933Srs200217 rr->uDNS_info.id = id;
4097*4b22b933Srs200217
4098*4b22b933Srs200217 // set zone
4099*4b22b933Srs200217 ptr = putZone(&msg, ptr, end, ®Info->zone, mDNSOpaque16fromIntVal(rr->resrec.rrclass));
4100*4b22b933Srs200217 if (!ptr) goto error;
4101*4b22b933Srs200217
4102*4b22b933Srs200217 if (regInfo->state == regState_UpdatePending)
4103*4b22b933Srs200217 {
4104*4b22b933Srs200217 // delete old RData
4105*4b22b933Srs200217 SetNewRData(&rr->resrec, regInfo->OrigRData, regInfo->OrigRDLen);
4106*4b22b933Srs200217 if (!(ptr = putDeletionRecord(&msg, ptr, &rr->resrec))) goto error; // delete old rdata
4107*4b22b933Srs200217
4108*4b22b933Srs200217 // add new RData
4109*4b22b933Srs200217 SetNewRData(&rr->resrec, regInfo->InFlightRData, regInfo->InFlightRDLen);
4110*4b22b933Srs200217 if (!(ptr = PutResourceRecordTTLJumbo(&msg, ptr, &msg.h.mDNS_numUpdates, &rr->resrec, rr->resrec.rroriginalttl))) goto error;
4111*4b22b933Srs200217 }
4112*4b22b933Srs200217
4113*4b22b933Srs200217 else
4114*4b22b933Srs200217 {
4115*4b22b933Srs200217 if (rr->resrec.RecordType == kDNSRecordTypeKnownUnique)
4116*4b22b933Srs200217 {
4117*4b22b933Srs200217 // KnownUnique: Delete any previous value
4118*4b22b933Srs200217 ptr = putDeleteRRSet(&msg, ptr, rr->resrec.name, rr->resrec.rrtype);
4119*4b22b933Srs200217 if (!ptr) goto error;
4120*4b22b933Srs200217 }
4121*4b22b933Srs200217
4122*4b22b933Srs200217 else if (rr->resrec.RecordType != kDNSRecordTypeShared)
4123*4b22b933Srs200217 {
4124*4b22b933Srs200217 ptr = putPrereqNameNotInUse(rr->resrec.name, &msg, ptr, end);
4125*4b22b933Srs200217 if (!ptr) goto error;
4126*4b22b933Srs200217 }
4127*4b22b933Srs200217
4128*4b22b933Srs200217 ptr = PutResourceRecordTTLJumbo(&msg, ptr, &msg.h.mDNS_numUpdates, &rr->resrec, rr->resrec.rroriginalttl);
4129*4b22b933Srs200217 if (!ptr) goto error;
4130*4b22b933Srs200217 }
4131*4b22b933Srs200217
4132*4b22b933Srs200217 if (rr->uDNS_info.lease)
4133*4b22b933Srs200217 { ptr = putUpdateLease(&msg, ptr, DEFAULT_UPDATE_LEASE); if (!ptr) goto error; }
4134*4b22b933Srs200217
4135*4b22b933Srs200217 err = mDNSSendDNSMessage(m, &msg, ptr, mDNSInterface_Any, ®Info->ns, regInfo->port, -1, GetAuthInfoForName(u, rr->resrec.name));
4136*4b22b933Srs200217 if (err) debugf("ERROR: sendRecordRegistration - mDNSSendDNSMessage - %ld", err);
4137*4b22b933Srs200217
4138*4b22b933Srs200217 SetRecordRetry(m, rr, err);
4139*4b22b933Srs200217
4140*4b22b933Srs200217 if (regInfo->state != regState_Refresh && regInfo->state != regState_DeregDeferred && regInfo->state != regState_UpdatePending)
4141*4b22b933Srs200217 regInfo->state = regState_Pending;
4142*4b22b933Srs200217
4143*4b22b933Srs200217 return;
4144*4b22b933Srs200217
4145*4b22b933Srs200217 error:
4146*4b22b933Srs200217 LogMsg("sendRecordRegistration: Error formatting message");
4147*4b22b933Srs200217 if (rr->uDNS_info.state != regState_Unregistered)
4148*4b22b933Srs200217 {
4149*4b22b933Srs200217 unlinkAR(&u->RecordRegistrations, rr);
4150*4b22b933Srs200217 rr->uDNS_info.state = regState_Unregistered;
4151*4b22b933Srs200217 }
4152*4b22b933Srs200217 m->mDNS_reentrancy++; // Increment to allow client to legally make mDNS API calls from the callback
4153*4b22b933Srs200217 if (rr->RecordCallback) rr->RecordCallback(m, rr, err);
4154*4b22b933Srs200217 m->mDNS_reentrancy--; // Decrement to block mDNS API calls again
4155*4b22b933Srs200217 // NOTE: not safe to touch any client structures here
4156*4b22b933Srs200217 }
4157*4b22b933Srs200217
RecordRegistrationCallback(mStatus err,mDNS * const m,void * authPtr,const AsyncOpResult * result)4158*4b22b933Srs200217 mDNSlocal void RecordRegistrationCallback(mStatus err, mDNS *const m, void *authPtr, const AsyncOpResult *result)
4159*4b22b933Srs200217 {
4160*4b22b933Srs200217 AuthRecord *newRR = (AuthRecord*)authPtr;
4161*4b22b933Srs200217 const zoneData_t *zoneData = mDNSNULL;
4162*4b22b933Srs200217 uDNS_GlobalInfo *u = &m->uDNS_info;
4163*4b22b933Srs200217 AuthRecord *ptr;
4164*4b22b933Srs200217
4165*4b22b933Srs200217 // make sure record is still in list
4166*4b22b933Srs200217 for (ptr = u->RecordRegistrations; ptr; ptr = ptr->next)
4167*4b22b933Srs200217 if (ptr == newRR) break;
4168*4b22b933Srs200217 if (!ptr) { LogMsg("RecordRegistrationCallback - RR no longer in list. Discarding."); return; }
4169*4b22b933Srs200217
4170*4b22b933Srs200217 // check error/result
4171*4b22b933Srs200217 if (err) { LogMsg("RecordRegistrationCallback: error %ld", err); goto error; }
4172*4b22b933Srs200217 if (!result) { LogMsg("ERROR: RecordRegistrationCallback invoked with NULL result and no error"); goto error; }
4173*4b22b933Srs200217 else zoneData = &result->zoneData;
4174*4b22b933Srs200217
4175*4b22b933Srs200217 if (newRR->uDNS_info.state == regState_Cancelled)
4176*4b22b933Srs200217 {
4177*4b22b933Srs200217 //!!!KRS we should send a memfree callback here!
4178*4b22b933Srs200217 debugf("Registration of %##s type %d cancelled prior to update",
4179*4b22b933Srs200217 newRR->resrec.name->c, newRR->resrec.rrtype);
4180*4b22b933Srs200217 newRR->uDNS_info.state = regState_Unregistered;
4181*4b22b933Srs200217 unlinkAR(&u->RecordRegistrations, newRR);
4182*4b22b933Srs200217 return;
4183*4b22b933Srs200217 }
4184*4b22b933Srs200217
4185*4b22b933Srs200217 if (result->type != zoneDataResult)
4186*4b22b933Srs200217 {
4187*4b22b933Srs200217 LogMsg("ERROR: buildUpdatePacket passed incorrect result type %d", result->type);
4188*4b22b933Srs200217 goto error;
4189*4b22b933Srs200217 }
4190*4b22b933Srs200217
4191*4b22b933Srs200217 if (newRR->resrec.rrclass != zoneData->zoneClass)
4192*4b22b933Srs200217 {
4193*4b22b933Srs200217 LogMsg("ERROR: New resource record's class (%d) does not match zone class (%d)",
4194*4b22b933Srs200217 newRR->resrec.rrclass, zoneData->zoneClass);
4195*4b22b933Srs200217 goto error;
4196*4b22b933Srs200217 }
4197*4b22b933Srs200217
4198*4b22b933Srs200217 // Don't try to do updates to the root name server.
4199*4b22b933Srs200217 // We might be tempted also to block updates to any single-label name server (e.g. com, edu, net, etc.) but some
4200*4b22b933Srs200217 // organizations use their own private pseudo-TLD, like ".home", etc, and we don't want to block that.
4201*4b22b933Srs200217 if (zoneData->zoneName.c[0] == 0)
4202*4b22b933Srs200217 {
4203*4b22b933Srs200217 LogMsg("ERROR: Only name server claiming responsibility for \"%##s\" is \"%##s\"!",
4204*4b22b933Srs200217 newRR->resrec.name->c, zoneData->zoneName.c);
4205*4b22b933Srs200217 err = mStatus_NoSuchNameErr;
4206*4b22b933Srs200217 goto error;
4207*4b22b933Srs200217 }
4208*4b22b933Srs200217
4209*4b22b933Srs200217 // cache zone data
4210*4b22b933Srs200217 AssignDomainName(&newRR->uDNS_info.zone, &zoneData->zoneName);
4211*4b22b933Srs200217 newRR->uDNS_info.ns = zoneData->primaryAddr;
4212*4b22b933Srs200217 if (zoneData->updatePort.NotAnInteger) newRR->uDNS_info.port = zoneData->updatePort;
4213*4b22b933Srs200217 else
4214*4b22b933Srs200217 {
4215*4b22b933Srs200217 debugf("Update port not advertised via SRV - guessing port 53, no lease option");
4216*4b22b933Srs200217 newRR->uDNS_info.port = UnicastDNSPort;
4217*4b22b933Srs200217 newRR->uDNS_info.lease = mDNSfalse;
4218*4b22b933Srs200217 }
4219*4b22b933Srs200217
4220*4b22b933Srs200217 sendRecordRegistration(m, newRR);
4221*4b22b933Srs200217 return;
4222*4b22b933Srs200217
4223*4b22b933Srs200217 error:
4224*4b22b933Srs200217 if (newRR->uDNS_info.state != regState_Unregistered)
4225*4b22b933Srs200217 {
4226*4b22b933Srs200217 unlinkAR(&u->RecordRegistrations, newRR);
4227*4b22b933Srs200217 newRR->uDNS_info.state = regState_Unregistered;
4228*4b22b933Srs200217 }
4229*4b22b933Srs200217 m->mDNS_reentrancy++; // Increment to allow client to legally make mDNS API calls from the callback
4230*4b22b933Srs200217 if (newRR->RecordCallback)
4231*4b22b933Srs200217 newRR->RecordCallback(m, newRR, err);
4232*4b22b933Srs200217 m->mDNS_reentrancy--; // Decrement to block mDNS API calls again
4233*4b22b933Srs200217 // NOTE: not safe to touch any client structures here
4234*4b22b933Srs200217 }
4235*4b22b933Srs200217
SendServiceRegistration(mDNS * m,ServiceRecordSet * srs)4236*4b22b933Srs200217 mDNSlocal void SendServiceRegistration(mDNS *m, ServiceRecordSet *srs)
4237*4b22b933Srs200217 {
4238*4b22b933Srs200217 DNSMessage msg;
4239*4b22b933Srs200217 mDNSu8 *ptr = msg.data;
4240*4b22b933Srs200217 mDNSu8 *end = (mDNSu8 *)&msg + sizeof(DNSMessage);
4241*4b22b933Srs200217 uDNS_GlobalInfo *u = &m->uDNS_info;
4242*4b22b933Srs200217 mDNSOpaque16 id;
4243*4b22b933Srs200217 uDNS_RegInfo *rInfo = &srs->uDNS_info;
4244*4b22b933Srs200217 mStatus err = mStatus_UnknownErr;
4245*4b22b933Srs200217 mDNSIPPort privport;
4246*4b22b933Srs200217 NATTraversalInfo *nat = srs->uDNS_info.NATinfo;
4247*4b22b933Srs200217 mDNSBool mapped = mDNSfalse;
4248*4b22b933Srs200217 domainname target;
4249*4b22b933Srs200217 AuthRecord *srv = &srs->RR_SRV;
4250*4b22b933Srs200217 mDNSu32 i;
4251*4b22b933Srs200217
4252*4b22b933Srs200217 privport = zeroIPPort;
4253*4b22b933Srs200217
4254*4b22b933Srs200217 if (!rInfo->ns.ip.v4.NotAnInteger) { LogMsg("SendServiceRegistration - NS not set!"); return; }
4255*4b22b933Srs200217
4256*4b22b933Srs200217 id = newMessageID(u);
4257*4b22b933Srs200217 InitializeDNSMessage(&msg.h, id, UpdateReqFlags);
4258*4b22b933Srs200217
4259*4b22b933Srs200217 // setup resource records
4260*4b22b933Srs200217 SetNewRData(&srs->RR_PTR.resrec, mDNSNULL, 0);
4261*4b22b933Srs200217 SetNewRData(&srs->RR_TXT.resrec, mDNSNULL, 0);
4262*4b22b933Srs200217
4263*4b22b933Srs200217 // replace port w/ NAT mapping if necessary
4264*4b22b933Srs200217 if (nat && nat->PublicPort.NotAnInteger &&
4265*4b22b933Srs200217 (nat->state == NATState_Established || nat->state == NATState_Refresh || nat->state == NATState_Legacy))
4266*4b22b933Srs200217 {
4267*4b22b933Srs200217 privport = srv->resrec.rdata->u.srv.port;
4268*4b22b933Srs200217 srv->resrec.rdata->u.srv.port = nat->PublicPort;
4269*4b22b933Srs200217 mapped = mDNStrue;
4270*4b22b933Srs200217 }
4271*4b22b933Srs200217
4272*4b22b933Srs200217 // construct update packet
4273*4b22b933Srs200217 // set zone
4274*4b22b933Srs200217 ptr = putZone(&msg, ptr, end, &rInfo->zone, mDNSOpaque16fromIntVal(srv->resrec.rrclass));
4275*4b22b933Srs200217 if (!ptr) goto error;
4276*4b22b933Srs200217
4277*4b22b933Srs200217 if (srs->uDNS_info.TestForSelfConflict)
4278*4b22b933Srs200217 {
4279*4b22b933Srs200217 // update w/ prereq that SRV already exist to make sure previous registration was ours, and delete any stale TXT records
4280*4b22b933Srs200217 if (!(ptr = PutResourceRecordTTLJumbo(&msg, ptr, &msg.h.mDNS_numPrereqs, &srs->RR_SRV.resrec, 0))) goto error;
4281*4b22b933Srs200217 if (!(ptr = putDeleteRRSet(&msg, ptr, srs->RR_TXT.resrec.name, srs->RR_TXT.resrec.rrtype))) goto error;
4282*4b22b933Srs200217 }
4283*4b22b933Srs200217
4284*4b22b933Srs200217 else if (srs->uDNS_info.state != regState_Refresh && srs->uDNS_info.state != regState_UpdatePending)
4285*4b22b933Srs200217 {
4286*4b22b933Srs200217 // use SRV name for prereq
4287*4b22b933Srs200217 ptr = putPrereqNameNotInUse(srv->resrec.name, &msg, ptr, end);
4288*4b22b933Srs200217 if (!ptr) goto error;
4289*4b22b933Srs200217 }
4290*4b22b933Srs200217
4291*4b22b933Srs200217 //!!!KRS Need to do bounds checking and use TCP if it won't fit!!!
4292*4b22b933Srs200217 if (!(ptr = PutResourceRecordTTLJumbo(&msg, ptr, &msg.h.mDNS_numUpdates, &srs->RR_PTR.resrec, srs->RR_PTR.resrec.rroriginalttl))) goto error;
4293*4b22b933Srs200217
4294*4b22b933Srs200217 for (i = 0; i < srs->NumSubTypes; i++)
4295*4b22b933Srs200217 if (!(ptr = PutResourceRecordTTLJumbo(&msg, ptr, &msg.h.mDNS_numUpdates, &srs->SubTypes[i].resrec, srs->SubTypes[i].resrec.rroriginalttl))) goto error;
4296*4b22b933Srs200217
4297*4b22b933Srs200217 if (rInfo->state == regState_UpdatePending) // we're updating the txt record
4298*4b22b933Srs200217 {
4299*4b22b933Srs200217 AuthRecord *txt = &srs->RR_TXT;
4300*4b22b933Srs200217 uDNS_RegInfo *txtInfo = &txt->uDNS_info;
4301*4b22b933Srs200217 // delete old RData
4302*4b22b933Srs200217 SetNewRData(&txt->resrec, txtInfo->OrigRData, txtInfo->OrigRDLen);
4303*4b22b933Srs200217 if (!(ptr = putDeletionRecord(&msg, ptr, &srs->RR_TXT.resrec))) goto error; // delete old rdata
4304*4b22b933Srs200217
4305*4b22b933Srs200217 // add new RData
4306*4b22b933Srs200217 SetNewRData(&txt->resrec, txtInfo->InFlightRData, txtInfo->InFlightRDLen);
4307*4b22b933Srs200217 if (!(ptr = PutResourceRecordTTLJumbo(&msg, ptr, &msg.h.mDNS_numUpdates, &srs->RR_TXT.resrec, srs->RR_TXT.resrec.rroriginalttl))) goto error;
4308*4b22b933Srs200217 }
4309*4b22b933Srs200217 else
4310*4b22b933Srs200217 if (!(ptr = PutResourceRecordTTLJumbo(&msg, ptr, &msg.h.mDNS_numUpdates, &srs->RR_TXT.resrec, srs->RR_TXT.resrec.rroriginalttl))) goto error;
4311*4b22b933Srs200217
4312*4b22b933Srs200217 if (!GetServiceTarget(u, srv, &target))
4313*4b22b933Srs200217 {
4314*4b22b933Srs200217 debugf("Couldn't get target for service %##s", srv->resrec.name->c);
4315*4b22b933Srs200217 rInfo->state = regState_NoTarget;
4316*4b22b933Srs200217 return;
4317*4b22b933Srs200217 }
4318*4b22b933Srs200217
4319*4b22b933Srs200217 if (!SameDomainName(&target, &srv->resrec.rdata->u.srv.target))
4320*4b22b933Srs200217 {
4321*4b22b933Srs200217 AssignDomainName(&srv->resrec.rdata->u.srv.target, &target);
4322*4b22b933Srs200217 SetNewRData(&srv->resrec, mDNSNULL, 0);
4323*4b22b933Srs200217 }
4324*4b22b933Srs200217
4325*4b22b933Srs200217 ptr = PutResourceRecordTTLJumbo(&msg, ptr, &msg.h.mDNS_numUpdates, &srv->resrec, srv->resrec.rroriginalttl);
4326*4b22b933Srs200217 if (!ptr) goto error;
4327*4b22b933Srs200217
4328*4b22b933Srs200217 if (srs->uDNS_info.lease)
4329*4b22b933Srs200217 { ptr = putUpdateLease(&msg, ptr, DEFAULT_UPDATE_LEASE); if (!ptr) goto error; }
4330*4b22b933Srs200217
4331*4b22b933Srs200217 err = mDNSSendDNSMessage(m, &msg, ptr, mDNSInterface_Any, &rInfo->ns, rInfo->port, -1, GetAuthInfoForName(u, srs->RR_SRV.resrec.name));
4332*4b22b933Srs200217 if (err) debugf("ERROR: SendServiceRegistration - mDNSSendDNSMessage - %ld", err);
4333*4b22b933Srs200217
4334*4b22b933Srs200217 if (rInfo->state != regState_Refresh && rInfo->state != regState_DeregDeferred && srs->uDNS_info.state != regState_UpdatePending)
4335*4b22b933Srs200217 rInfo->state = regState_Pending;
4336*4b22b933Srs200217
4337*4b22b933Srs200217 SetRecordRetry(m, &srs->RR_SRV, err);
4338*4b22b933Srs200217 rInfo->id = id;
4339*4b22b933Srs200217 if (mapped) srv->resrec.rdata->u.srv.port = privport;
4340*4b22b933Srs200217 return;
4341*4b22b933Srs200217
4342*4b22b933Srs200217 error:
4343*4b22b933Srs200217 LogMsg("SendServiceRegistration - Error formatting message");
4344*4b22b933Srs200217 if (mapped) srv->resrec.rdata->u.srv.port = privport;
4345*4b22b933Srs200217 unlinkSRS(m, srs);
4346*4b22b933Srs200217 rInfo->state = regState_Unregistered;
4347*4b22b933Srs200217 m->mDNS_reentrancy++; // Increment to allow client to legally make mDNS API calls from the callback
4348*4b22b933Srs200217 srs->ServiceCallback(m, srs, err);
4349*4b22b933Srs200217 m->mDNS_reentrancy--; // Decrement to block mDNS API calls again
4350*4b22b933Srs200217 //!!!KRS will mem still be free'd on error?
4351*4b22b933Srs200217 // NOTE: not safe to touch any client structures here
4352*4b22b933Srs200217 }
4353*4b22b933Srs200217
serviceRegistrationCallback(mStatus err,mDNS * const m,void * srsPtr,const AsyncOpResult * result)4354*4b22b933Srs200217 mDNSlocal void serviceRegistrationCallback(mStatus err, mDNS *const m, void *srsPtr, const AsyncOpResult *result)
4355*4b22b933Srs200217 {
4356*4b22b933Srs200217 ServiceRecordSet *srs = (ServiceRecordSet *)srsPtr;
4357*4b22b933Srs200217 const zoneData_t *zoneData = mDNSNULL;
4358*4b22b933Srs200217
4359*4b22b933Srs200217 if (err) goto error;
4360*4b22b933Srs200217 if (!result) { LogMsg("ERROR: serviceRegistrationCallback invoked with NULL result and no error"); goto error; }
4361*4b22b933Srs200217 else zoneData = &result->zoneData;
4362*4b22b933Srs200217
4363*4b22b933Srs200217 if (result->type != zoneDataResult)
4364*4b22b933Srs200217 {
4365*4b22b933Srs200217 LogMsg("ERROR: buildUpdatePacket passed incorrect result type %d", result->type);
4366*4b22b933Srs200217 goto error;
4367*4b22b933Srs200217 }
4368*4b22b933Srs200217
4369*4b22b933Srs200217 if (srs->uDNS_info.state == regState_Cancelled)
4370*4b22b933Srs200217 {
4371*4b22b933Srs200217 // client cancelled registration while fetching zone data
4372*4b22b933Srs200217 srs->uDNS_info.state = regState_Unregistered;
4373*4b22b933Srs200217 unlinkSRS(m, srs);
4374*4b22b933Srs200217 m->mDNS_reentrancy++; // Increment to allow client to legally make mDNS API calls from the callback
4375*4b22b933Srs200217 srs->ServiceCallback(m, srs, mStatus_MemFree);
4376*4b22b933Srs200217 m->mDNS_reentrancy--; // Decrement to block mDNS API calls again
4377*4b22b933Srs200217 return;
4378*4b22b933Srs200217 }
4379*4b22b933Srs200217
4380*4b22b933Srs200217 if (srs->RR_SRV.resrec.rrclass != zoneData->zoneClass)
4381*4b22b933Srs200217 {
4382*4b22b933Srs200217 LogMsg("Service %##s - class does not match zone", srs->RR_SRV.resrec.name->c);
4383*4b22b933Srs200217 goto error;
4384*4b22b933Srs200217 }
4385*4b22b933Srs200217
4386*4b22b933Srs200217 // cache zone data
4387*4b22b933Srs200217 AssignDomainName(&srs->uDNS_info.zone, &zoneData->zoneName);
4388*4b22b933Srs200217 srs->uDNS_info.ns.type = mDNSAddrType_IPv4;
4389*4b22b933Srs200217 srs->uDNS_info.ns = zoneData->primaryAddr;
4390*4b22b933Srs200217 if (zoneData->updatePort.NotAnInteger) srs->uDNS_info.port = zoneData->updatePort;
4391*4b22b933Srs200217 else
4392*4b22b933Srs200217 {
4393*4b22b933Srs200217 debugf("Update port not advertised via SRV - guessing port 53, no lease option");
4394*4b22b933Srs200217 srs->uDNS_info.port = UnicastDNSPort;
4395*4b22b933Srs200217 srs->uDNS_info.lease = mDNSfalse;
4396*4b22b933Srs200217 }
4397*4b22b933Srs200217
4398*4b22b933Srs200217 if (srs->RR_SRV.resrec.rdata->u.srv.port.NotAnInteger && IsPrivateV4Addr(&m->uDNS_info.AdvertisedV4))
4399*4b22b933Srs200217 { srs->uDNS_info.state = regState_NATMap; StartNATPortMap(m, srs); }
4400*4b22b933Srs200217 else SendServiceRegistration(m, srs);
4401*4b22b933Srs200217 return;
4402*4b22b933Srs200217
4403*4b22b933Srs200217 error:
4404*4b22b933Srs200217 unlinkSRS(m, srs);
4405*4b22b933Srs200217 srs->uDNS_info.state = regState_Unregistered;
4406*4b22b933Srs200217 m->mDNS_reentrancy++; // Increment to allow client to legally make mDNS API calls from the callback
4407*4b22b933Srs200217 srs->ServiceCallback(m, srs, err);
4408*4b22b933Srs200217 m->mDNS_reentrancy--; // Decrement to block mDNS API calls again
4409*4b22b933Srs200217 // NOTE: not safe to touch any client structures here
4410*4b22b933Srs200217 }
4411*4b22b933Srs200217
SetupRecordRegistration(mDNS * m,AuthRecord * rr)4412*4b22b933Srs200217 mDNSlocal mStatus SetupRecordRegistration(mDNS *m, AuthRecord *rr)
4413*4b22b933Srs200217 {
4414*4b22b933Srs200217 domainname *target = GetRRDomainNameTarget(&rr->resrec);
4415*4b22b933Srs200217 AuthRecord *ptr = m->uDNS_info.RecordRegistrations;
4416*4b22b933Srs200217
4417*4b22b933Srs200217 while (ptr && ptr != rr) ptr = ptr->next;
4418*4b22b933Srs200217 if (ptr) { LogMsg("Error: SetupRecordRegistration - record %##s already in list!", rr->resrec.name->c); return mStatus_AlreadyRegistered; }
4419*4b22b933Srs200217
4420*4b22b933Srs200217 if (rr->uDNS_info.state == regState_FetchingZoneData ||
4421*4b22b933Srs200217 rr->uDNS_info.state == regState_Pending ||
4422*4b22b933Srs200217 rr->uDNS_info.state == regState_Registered)
4423*4b22b933Srs200217 {
4424*4b22b933Srs200217 LogMsg("Requested double-registration of physical record %##s type %d",
4425*4b22b933Srs200217 rr->resrec.name->c, rr->resrec.rrtype);
4426*4b22b933Srs200217 return mStatus_AlreadyRegistered;
4427*4b22b933Srs200217 }
4428*4b22b933Srs200217
4429*4b22b933Srs200217 rr->resrec.rdlength = GetRDLength(&rr->resrec, mDNSfalse);
4430*4b22b933Srs200217 rr->resrec.rdestimate = GetRDLength(&rr->resrec, mDNStrue);
4431*4b22b933Srs200217
4432*4b22b933Srs200217 if (!ValidateDomainName(rr->resrec.name))
4433*4b22b933Srs200217 {
4434*4b22b933Srs200217 LogMsg("Attempt to register record with invalid name: %s", ARDisplayString(m, rr));
4435*4b22b933Srs200217 return mStatus_Invalid;
4436*4b22b933Srs200217 }
4437*4b22b933Srs200217
4438*4b22b933Srs200217 // Don't do this until *after* we've set rr->resrec.rdlength
4439*4b22b933Srs200217 if (!ValidateRData(rr->resrec.rrtype, rr->resrec.rdlength, rr->resrec.rdata))
4440*4b22b933Srs200217 {
4441*4b22b933Srs200217 LogMsg("Attempt to register record with invalid rdata: %s", ARDisplayString(m, rr));
4442*4b22b933Srs200217 return mStatus_Invalid;
4443*4b22b933Srs200217 }
4444*4b22b933Srs200217
4445*4b22b933Srs200217 rr->resrec.namehash = DomainNameHashValue(rr->resrec.name);
4446*4b22b933Srs200217 rr->resrec.rdatahash = target ? DomainNameHashValue(target) : RDataHashValue(rr->resrec.rdlength, &rr->resrec.rdata->u);
4447*4b22b933Srs200217
4448*4b22b933Srs200217 rr->uDNS_info.state = regState_FetchingZoneData;
4449*4b22b933Srs200217 rr->next = m->uDNS_info.RecordRegistrations;
4450*4b22b933Srs200217 m->uDNS_info.RecordRegistrations = rr;
4451*4b22b933Srs200217 rr->uDNS_info.lease = mDNStrue;
4452*4b22b933Srs200217
4453*4b22b933Srs200217 return mStatus_NoError;
4454*4b22b933Srs200217 }
4455*4b22b933Srs200217
uDNS_RegisterRecord(mDNS * const m,AuthRecord * const rr)4456*4b22b933Srs200217 mDNSexport mStatus uDNS_RegisterRecord(mDNS *const m, AuthRecord *const rr)
4457*4b22b933Srs200217 {
4458*4b22b933Srs200217 mStatus err = SetupRecordRegistration(m, rr);
4459*4b22b933Srs200217 if (err) return err;
4460*4b22b933Srs200217 else return startGetZoneData(rr->resrec.name, m, mDNStrue, mDNSfalse, RecordRegistrationCallback, rr);
4461*4b22b933Srs200217 }
4462*4b22b933Srs200217
SendRecordDeregistration(mDNS * m,AuthRecord * rr)4463*4b22b933Srs200217 mDNSlocal void SendRecordDeregistration(mDNS *m, AuthRecord *rr)
4464*4b22b933Srs200217 {
4465*4b22b933Srs200217 uDNS_GlobalInfo *u = &m->uDNS_info;
4466*4b22b933Srs200217 DNSMessage msg;
4467*4b22b933Srs200217 mDNSu8 *ptr = msg.data;
4468*4b22b933Srs200217 mDNSu8 *end = (mDNSu8 *)&msg + sizeof(DNSMessage);
4469*4b22b933Srs200217 mStatus err;
4470*4b22b933Srs200217
4471*4b22b933Srs200217 InitializeDNSMessage(&msg.h, rr->uDNS_info.id, UpdateReqFlags);
4472*4b22b933Srs200217
4473*4b22b933Srs200217 ptr = putZone(&msg, ptr, end, &rr->uDNS_info.zone, mDNSOpaque16fromIntVal(rr->resrec.rrclass));
4474*4b22b933Srs200217 if (!ptr) goto error;
4475*4b22b933Srs200217 if (!(ptr = putDeletionRecord(&msg, ptr, &rr->resrec))) goto error;
4476*4b22b933Srs200217
4477*4b22b933Srs200217 err = mDNSSendDNSMessage(m, &msg, ptr, mDNSInterface_Any, &rr->uDNS_info.ns, rr->uDNS_info.port, -1, GetAuthInfoForName(u, rr->resrec.name));
4478*4b22b933Srs200217 if (err) debugf("ERROR: SendRecordDeregistration - mDNSSendDNSMessage - %ld", err);
4479*4b22b933Srs200217
4480*4b22b933Srs200217 SetRecordRetry(m, rr, err);
4481*4b22b933Srs200217 rr->uDNS_info.state = regState_DeregPending;
4482*4b22b933Srs200217 return;
4483*4b22b933Srs200217
4484*4b22b933Srs200217 error:
4485*4b22b933Srs200217 LogMsg("Error: SendRecordDeregistration - could not contruct deregistration packet");
4486*4b22b933Srs200217 unlinkAR(&u->RecordRegistrations, rr);
4487*4b22b933Srs200217 rr->uDNS_info.state = regState_Unregistered;
4488*4b22b933Srs200217 }
4489*4b22b933Srs200217
4490*4b22b933Srs200217
4491*4b22b933Srs200217
uDNS_DeregisterRecord(mDNS * const m,AuthRecord * const rr)4492*4b22b933Srs200217 mDNSexport mStatus uDNS_DeregisterRecord(mDNS *const m, AuthRecord *const rr)
4493*4b22b933Srs200217 {
4494*4b22b933Srs200217 uDNS_GlobalInfo *u = &m->uDNS_info;
4495*4b22b933Srs200217 NATTraversalInfo *n = rr->uDNS_info.NATinfo;
4496*4b22b933Srs200217
4497*4b22b933Srs200217 switch (rr->uDNS_info.state)
4498*4b22b933Srs200217 {
4499*4b22b933Srs200217 case regState_NATMap:
4500*4b22b933Srs200217 // we're in the middle of a NAT traversal operation
4501*4b22b933Srs200217 rr->uDNS_info.NATinfo = mDNSNULL;
4502*4b22b933Srs200217 if (!n) LogMsg("uDNS_DeregisterRecord: no NAT info context");
4503*4b22b933Srs200217 else FreeNATInfo(m, n); // cause response to outstanding request to be ignored.
4504*4b22b933Srs200217 // Note: normally here we're trying to determine our public address,
4505*4b22b933Srs200217 //in which case there is not state to be torn down. For simplicity,
4506*4b22b933Srs200217 //we allow other operations to expire.
4507*4b22b933Srs200217 rr->uDNS_info.state = regState_Unregistered;
4508*4b22b933Srs200217 break;
4509*4b22b933Srs200217 case regState_ExtraQueued:
4510*4b22b933Srs200217 rr->uDNS_info.state = regState_Unregistered;
4511*4b22b933Srs200217 break;
4512*4b22b933Srs200217 case regState_FetchingZoneData:
4513*4b22b933Srs200217 rr->uDNS_info.state = regState_Cancelled;
4514*4b22b933Srs200217 return mStatus_NoError;
4515*4b22b933Srs200217 case regState_Refresh:
4516*4b22b933Srs200217 case regState_Pending:
4517*4b22b933Srs200217 case regState_UpdatePending:
4518*4b22b933Srs200217 rr->uDNS_info.state = regState_DeregDeferred;
4519*4b22b933Srs200217 LogMsg("Deferring deregistration of record %##s until registration completes", rr->resrec.name->c);
4520*4b22b933Srs200217 return mStatus_NoError;
4521*4b22b933Srs200217 case regState_Registered:
4522*4b22b933Srs200217 case regState_DeregPending:
4523*4b22b933Srs200217 break;
4524*4b22b933Srs200217 case regState_DeregDeferred:
4525*4b22b933Srs200217 case regState_Cancelled:
4526*4b22b933Srs200217 LogMsg("Double deregistration of record %##s type %d",
4527*4b22b933Srs200217 rr->resrec.name->c, rr->resrec.rrtype);
4528*4b22b933Srs200217 return mStatus_UnknownErr;
4529*4b22b933Srs200217 case regState_Unregistered:
4530*4b22b933Srs200217 LogMsg("Requested deregistration of unregistered record %##s type %d",
4531*4b22b933Srs200217 rr->resrec.name->c, rr->resrec.rrtype);
4532*4b22b933Srs200217 return mStatus_UnknownErr;
4533*4b22b933Srs200217 case regState_NATError:
4534*4b22b933Srs200217 case regState_NoTarget:
4535*4b22b933Srs200217 LogMsg("ERROR: uDNS_DeregisterRecord called for record %##s with bad state %s", rr->resrec.name->c, rr->uDNS_info.state == regState_NoTarget ? "regState_NoTarget" : "regState_NATError");
4536*4b22b933Srs200217 return mStatus_UnknownErr;
4537*4b22b933Srs200217 }
4538*4b22b933Srs200217
4539*4b22b933Srs200217 if (rr->uDNS_info.state == regState_Unregistered)
4540*4b22b933Srs200217 {
4541*4b22b933Srs200217 // unlink and deliver memfree
4542*4b22b933Srs200217
4543*4b22b933Srs200217 unlinkAR(&u->RecordRegistrations, rr);
4544*4b22b933Srs200217 m->mDNS_reentrancy++; // Increment to allow client to legally make mDNS API calls from the callback
4545*4b22b933Srs200217 if (rr->RecordCallback) rr->RecordCallback(m, rr, mStatus_MemFree);
4546*4b22b933Srs200217 m->mDNS_reentrancy--; // Decrement to block mDNS API calls again
4547*4b22b933Srs200217 return mStatus_NoError;
4548*4b22b933Srs200217 }
4549*4b22b933Srs200217
4550*4b22b933Srs200217 rr->uDNS_info.NATinfo = mDNSNULL;
4551*4b22b933Srs200217 if (n) FreeNATInfo(m, n);
4552*4b22b933Srs200217
4553*4b22b933Srs200217 SendRecordDeregistration(m, rr);
4554*4b22b933Srs200217 return mStatus_NoError;
4555*4b22b933Srs200217 }
4556*4b22b933Srs200217
uDNS_RegisterService(mDNS * const m,ServiceRecordSet * srs)4557*4b22b933Srs200217 mDNSexport mStatus uDNS_RegisterService(mDNS *const m, ServiceRecordSet *srs)
4558*4b22b933Srs200217 {
4559*4b22b933Srs200217 mDNSu32 i;
4560*4b22b933Srs200217 domainname target;
4561*4b22b933Srs200217 uDNS_RegInfo *info = &srs->uDNS_info;
4562*4b22b933Srs200217 ServiceRecordSet **p = &m->uDNS_info.ServiceRegistrations;
4563*4b22b933Srs200217 while (*p && *p != srs) p=&(*p)->next;
4564*4b22b933Srs200217 if (*p) { LogMsg("uDNS_RegisterService: %p %##s already in list", srs, srs->RR_SRV.resrec.name->c); return(mStatus_AlreadyRegistered); }
4565*4b22b933Srs200217 ubzero(info, sizeof(*info));
4566*4b22b933Srs200217 *p = srs;
4567*4b22b933Srs200217 srs->next = mDNSNULL;
4568*4b22b933Srs200217
4569*4b22b933Srs200217 srs->RR_SRV.resrec.rroriginalttl = kWideAreaTTL;
4570*4b22b933Srs200217 srs->RR_TXT.resrec.rroriginalttl = kWideAreaTTL;
4571*4b22b933Srs200217 srs->RR_PTR.resrec.rroriginalttl = kWideAreaTTL;
4572*4b22b933Srs200217 for (i = 0; i < srs->NumSubTypes;i++) srs->SubTypes[i].resrec.rroriginalttl = kWideAreaTTL;
4573*4b22b933Srs200217
4574*4b22b933Srs200217 info->lease = mDNStrue;
4575*4b22b933Srs200217
4576*4b22b933Srs200217 srs->RR_SRV.resrec.rdata->u.srv.target.c[0] = 0;
4577*4b22b933Srs200217 if (!GetServiceTarget(&m->uDNS_info, &srs->RR_SRV, &target))
4578*4b22b933Srs200217 {
4579*4b22b933Srs200217 // defer registration until we've got a target
4580*4b22b933Srs200217 debugf("uDNS_RegisterService - no target for %##s", srs->RR_SRV.resrec.name->c);
4581*4b22b933Srs200217 info->state = regState_NoTarget;
4582*4b22b933Srs200217 return mStatus_NoError;
4583*4b22b933Srs200217 }
4584*4b22b933Srs200217
4585*4b22b933Srs200217 info->state = regState_FetchingZoneData;
4586*4b22b933Srs200217 return startGetZoneData(srs->RR_SRV.resrec.name, m, mDNStrue, mDNSfalse, serviceRegistrationCallback, srs);
4587*4b22b933Srs200217 }
4588*4b22b933Srs200217
SendServiceDeregistration(mDNS * m,ServiceRecordSet * srs)4589*4b22b933Srs200217 mDNSlocal void SendServiceDeregistration(mDNS *m, ServiceRecordSet *srs)
4590*4b22b933Srs200217 {
4591*4b22b933Srs200217 uDNS_RegInfo *info = &srs->uDNS_info;
4592*4b22b933Srs200217 uDNS_GlobalInfo *u = &m->uDNS_info;
4593*4b22b933Srs200217 DNSMessage msg;
4594*4b22b933Srs200217 mDNSOpaque16 id;
4595*4b22b933Srs200217 mDNSu8 *ptr = msg.data;
4596*4b22b933Srs200217 mDNSu8 *end = (mDNSu8 *)&msg + sizeof(DNSMessage);
4597*4b22b933Srs200217 mStatus err = mStatus_UnknownErr;
4598*4b22b933Srs200217 mDNSu32 i;
4599*4b22b933Srs200217
4600*4b22b933Srs200217 id = newMessageID(u);
4601*4b22b933Srs200217 InitializeDNSMessage(&msg.h, id, UpdateReqFlags);
4602*4b22b933Srs200217
4603*4b22b933Srs200217 // put zone
4604*4b22b933Srs200217 ptr = putZone(&msg, ptr, end, &info->zone, mDNSOpaque16fromIntVal(srs->RR_SRV.resrec.rrclass));
4605*4b22b933Srs200217 if (!ptr) { LogMsg("ERROR: SendServiceDeregistration - putZone"); goto error; }
4606*4b22b933Srs200217
4607*4b22b933Srs200217 if (!(ptr = putDeleteAllRRSets(&msg, ptr, srs->RR_SRV.resrec.name))) goto error; // this deletes SRV, TXT, and Extras
4608*4b22b933Srs200217 if (!(ptr = putDeletionRecord(&msg, ptr, &srs->RR_PTR.resrec))) goto error;
4609*4b22b933Srs200217 for (i = 0; i < srs->NumSubTypes; i++)
4610*4b22b933Srs200217 if (!(ptr = putDeletionRecord(&msg, ptr, &srs->SubTypes[i].resrec))) goto error;
4611*4b22b933Srs200217
4612*4b22b933Srs200217
4613*4b22b933Srs200217 err = mDNSSendDNSMessage(m, &msg, ptr, mDNSInterface_Any, &info->ns, info->port, -1, GetAuthInfoForName(u, srs->RR_SRV.resrec.name));
4614*4b22b933Srs200217 if (err && err != mStatus_TransientErr) { debugf("ERROR: SendServiceDeregistration - mDNSSendDNSMessage - %ld", err); goto error; }
4615*4b22b933Srs200217
4616*4b22b933Srs200217 SetRecordRetry(m, &srs->RR_SRV, err);
4617*4b22b933Srs200217 info->id = id;
4618*4b22b933Srs200217 info->state = regState_DeregPending;
4619*4b22b933Srs200217
4620*4b22b933Srs200217 return;
4621*4b22b933Srs200217
4622*4b22b933Srs200217 error:
4623*4b22b933Srs200217 unlinkSRS(m, srs);
4624*4b22b933Srs200217 info->state = regState_Unregistered;
4625*4b22b933Srs200217 }
4626*4b22b933Srs200217
uDNS_DeregisterService(mDNS * const m,ServiceRecordSet * srs)4627*4b22b933Srs200217 mDNSexport mStatus uDNS_DeregisterService(mDNS *const m, ServiceRecordSet *srs)
4628*4b22b933Srs200217 {
4629*4b22b933Srs200217 NATTraversalInfo *nat = srs->uDNS_info.NATinfo;
4630*4b22b933Srs200217 char *errmsg = "Unknown State";
4631*4b22b933Srs200217
4632*4b22b933Srs200217 // don't re-register with a new target following deregistration
4633*4b22b933Srs200217 srs->uDNS_info.SRVChanged = srs->uDNS_info.SRVUpdateDeferred = mDNSfalse;
4634*4b22b933Srs200217
4635*4b22b933Srs200217 if (nat)
4636*4b22b933Srs200217 {
4637*4b22b933Srs200217 if (nat->state == NATState_Established || nat->state == NATState_Refresh || nat->state == NATState_Legacy)
4638*4b22b933Srs200217 DeleteNATPortMapping(m, nat, srs);
4639*4b22b933Srs200217 nat->reg.ServiceRegistration = mDNSNULL;
4640*4b22b933Srs200217 srs->uDNS_info.NATinfo = mDNSNULL;
4641*4b22b933Srs200217 FreeNATInfo(m, nat);
4642*4b22b933Srs200217 }
4643*4b22b933Srs200217
4644*4b22b933Srs200217 switch (srs->uDNS_info.state)
4645*4b22b933Srs200217 {
4646*4b22b933Srs200217 case regState_Unregistered:
4647*4b22b933Srs200217 debugf("uDNS_DeregisterService - service %##s not registered", srs->RR_SRV.resrec.name->c);
4648*4b22b933Srs200217 return mStatus_BadReferenceErr;
4649*4b22b933Srs200217 case regState_FetchingZoneData:
4650*4b22b933Srs200217 // let the async op complete, then terminate
4651*4b22b933Srs200217 srs->uDNS_info.state = regState_Cancelled;
4652*4b22b933Srs200217 return mStatus_NoError; // deliver memfree upon completion of async op
4653*4b22b933Srs200217 case regState_Pending:
4654*4b22b933Srs200217 case regState_Refresh:
4655*4b22b933Srs200217 case regState_UpdatePending:
4656*4b22b933Srs200217 // deregister following completion of in-flight operation
4657*4b22b933Srs200217 srs->uDNS_info.state = regState_DeregDeferred;
4658*4b22b933Srs200217 return mStatus_NoError;
4659*4b22b933Srs200217 case regState_DeregPending:
4660*4b22b933Srs200217 case regState_DeregDeferred:
4661*4b22b933Srs200217 case regState_Cancelled:
4662*4b22b933Srs200217 debugf("Double deregistration of service %##s", srs->RR_SRV.resrec.name->c);
4663*4b22b933Srs200217 return mStatus_NoError;
4664*4b22b933Srs200217 case regState_NATError: // not registered
4665*4b22b933Srs200217 case regState_NATMap: // not registered
4666*4b22b933Srs200217 case regState_NoTarget: // not registered
4667*4b22b933Srs200217 unlinkSRS(m, srs);
4668*4b22b933Srs200217 srs->uDNS_info.state = regState_Unregistered;
4669*4b22b933Srs200217 m->mDNS_reentrancy++; // Increment to allow client to legally make mDNS API calls from the callback
4670*4b22b933Srs200217 srs->ServiceCallback(m, srs, mStatus_MemFree);
4671*4b22b933Srs200217 m->mDNS_reentrancy--; // Decrement to block mDNS API calls again
4672*4b22b933Srs200217 return mStatus_NoError;
4673*4b22b933Srs200217 case regState_Registered:
4674*4b22b933Srs200217 srs->uDNS_info.state = regState_DeregPending;
4675*4b22b933Srs200217 SendServiceDeregistration(m, srs);
4676*4b22b933Srs200217 return mStatus_NoError;
4677*4b22b933Srs200217 case regState_ExtraQueued: // only for record registrations
4678*4b22b933Srs200217 errmsg = "bad state (regState_ExtraQueued)";
4679*4b22b933Srs200217 goto error;
4680*4b22b933Srs200217 }
4681*4b22b933Srs200217
4682*4b22b933Srs200217 error:
4683*4b22b933Srs200217 LogMsg("Error, uDNS_DeregisterService: %s", errmsg);
4684*4b22b933Srs200217 return mStatus_BadReferenceErr;
4685*4b22b933Srs200217 }
4686*4b22b933Srs200217
uDNS_AddRecordToService(mDNS * const m,ServiceRecordSet * sr,ExtraResourceRecord * extra)4687*4b22b933Srs200217 mDNSexport mStatus uDNS_AddRecordToService(mDNS *const m, ServiceRecordSet *sr, ExtraResourceRecord *extra)
4688*4b22b933Srs200217 {
4689*4b22b933Srs200217 mStatus err = mStatus_UnknownErr;
4690*4b22b933Srs200217
4691*4b22b933Srs200217 extra->r.resrec.RecordType = kDNSRecordTypeShared; // don't want it to conflict with the service name
4692*4b22b933Srs200217 extra->r.RecordCallback = mDNSNULL; // don't generate callbacks for extra RRs
4693*4b22b933Srs200217
4694*4b22b933Srs200217 if (sr->uDNS_info.state == regState_Registered || sr->uDNS_info.state == regState_Refresh)
4695*4b22b933Srs200217 err = uDNS_RegisterRecord(m, &extra->r);
4696*4b22b933Srs200217 else
4697*4b22b933Srs200217 {
4698*4b22b933Srs200217 err = SetupRecordRegistration(m, &extra->r);
4699*4b22b933Srs200217 extra->r.uDNS_info.state = regState_ExtraQueued; // %%% Is it okay to overwrite the previous uDNS_info.state?
4700*4b22b933Srs200217 }
4701*4b22b933Srs200217
4702*4b22b933Srs200217 if (!err)
4703*4b22b933Srs200217 {
4704*4b22b933Srs200217 extra->next = sr->Extras;
4705*4b22b933Srs200217 sr->Extras = extra;
4706*4b22b933Srs200217 }
4707*4b22b933Srs200217 return err;
4708*4b22b933Srs200217 }
4709*4b22b933Srs200217
uDNS_UpdateRecord(mDNS * m,AuthRecord * rr)4710*4b22b933Srs200217 mDNSexport mStatus uDNS_UpdateRecord(mDNS *m, AuthRecord *rr)
4711*4b22b933Srs200217 {
4712*4b22b933Srs200217 uDNS_GlobalInfo *u = &m->uDNS_info;
4713*4b22b933Srs200217 ServiceRecordSet *parent = mDNSNULL;
4714*4b22b933Srs200217 AuthRecord *rptr;
4715*4b22b933Srs200217 uDNS_RegInfo *info = &rr->uDNS_info;
4716*4b22b933Srs200217 regState_t *stateptr = mDNSNULL;
4717*4b22b933Srs200217
4718*4b22b933Srs200217 // find the record in registered service list
4719*4b22b933Srs200217 for (parent = u->ServiceRegistrations; parent; parent = parent->next)
4720*4b22b933Srs200217 if (&parent->RR_TXT == rr) { stateptr = &parent->uDNS_info.state; break; }
4721*4b22b933Srs200217
4722*4b22b933Srs200217 if (!parent)
4723*4b22b933Srs200217 {
4724*4b22b933Srs200217 // record not part of a service - check individual record registrations
4725*4b22b933Srs200217 for (rptr = u->RecordRegistrations; rptr; rptr = rptr->next)
4726*4b22b933Srs200217 if (rptr == rr) { stateptr = &rr->uDNS_info.state; break; }
4727*4b22b933Srs200217 if (!rptr) goto unreg_error;
4728*4b22b933Srs200217 }
4729*4b22b933Srs200217
4730*4b22b933Srs200217 switch(*stateptr)
4731*4b22b933Srs200217 {
4732*4b22b933Srs200217 case regState_DeregPending:
4733*4b22b933Srs200217 case regState_DeregDeferred:
4734*4b22b933Srs200217 case regState_Cancelled:
4735*4b22b933Srs200217 case regState_Unregistered:
4736*4b22b933Srs200217 // not actively registered
4737*4b22b933Srs200217 goto unreg_error;
4738*4b22b933Srs200217
4739*4b22b933Srs200217 case regState_FetchingZoneData:
4740*4b22b933Srs200217 case regState_NATMap:
4741*4b22b933Srs200217 case regState_ExtraQueued:
4742*4b22b933Srs200217 case regState_NoTarget:
4743*4b22b933Srs200217 // change rdata directly since it hasn't been sent yet
4744*4b22b933Srs200217 if (info->UpdateRDCallback) info->UpdateRDCallback(m, rr, rr->resrec.rdata);
4745*4b22b933Srs200217 SetNewRData(&rr->resrec, rr->NewRData, rr->newrdlength);
4746*4b22b933Srs200217 rr->NewRData = mDNSNULL;
4747*4b22b933Srs200217 return mStatus_NoError;
4748*4b22b933Srs200217
4749*4b22b933Srs200217 case regState_Pending:
4750*4b22b933Srs200217 case regState_Refresh:
4751*4b22b933Srs200217 case regState_UpdatePending:
4752*4b22b933Srs200217 // registration in-flight. queue rdata and return
4753*4b22b933Srs200217 if (info->QueuedRData && info->UpdateRDCallback)
4754*4b22b933Srs200217 // if unsent rdata is already queued, free it before we replace it
4755*4b22b933Srs200217 info->UpdateRDCallback(m, rr, info->QueuedRData);
4756*4b22b933Srs200217 info->QueuedRData = rr->NewRData;
4757*4b22b933Srs200217 info->QueuedRDLen = rr->newrdlength;
4758*4b22b933Srs200217 rr->NewRData = mDNSNULL;
4759*4b22b933Srs200217 return mStatus_NoError;
4760*4b22b933Srs200217
4761*4b22b933Srs200217 case regState_Registered:
4762*4b22b933Srs200217 info->OrigRData = rr->resrec.rdata;
4763*4b22b933Srs200217 info->OrigRDLen = rr->resrec.rdlength;
4764*4b22b933Srs200217 info->InFlightRData = rr->NewRData;
4765*4b22b933Srs200217 info->InFlightRDLen = rr->newrdlength;
4766*4b22b933Srs200217 rr->NewRData = mDNSNULL;
4767*4b22b933Srs200217 *stateptr = regState_UpdatePending;
4768*4b22b933Srs200217 if (parent) SendServiceRegistration(m, parent);
4769*4b22b933Srs200217 else sendRecordRegistration(m, rr);
4770*4b22b933Srs200217 return mStatus_NoError;
4771*4b22b933Srs200217
4772*4b22b933Srs200217 case regState_NATError:
4773*4b22b933Srs200217 LogMsg("ERROR: uDNS_UpdateRecord called for record %##s with bad state regState_NATError", rr->resrec.name->c);
4774*4b22b933Srs200217 return mStatus_UnknownErr; // states for service records only
4775*4b22b933Srs200217 }
4776*4b22b933Srs200217
4777*4b22b933Srs200217 unreg_error:
4778*4b22b933Srs200217 LogMsg("Requested update of record %##s type %d, part of service not currently registered",
4779*4b22b933Srs200217 rr->resrec.name->c, rr->resrec.rrtype);
4780*4b22b933Srs200217 return mStatus_Invalid;
4781*4b22b933Srs200217 }
4782*4b22b933Srs200217
4783*4b22b933Srs200217
4784*4b22b933Srs200217 // ***************************************************************************
4785*4b22b933Srs200217 #if COMPILER_LIKES_PRAGMA_MARK
4786*4b22b933Srs200217 #pragma mark - Periodic Execution Routines
4787*4b22b933Srs200217 #endif
4788*4b22b933Srs200217
4789*4b22b933Srs200217
CheckNATMappings(mDNS * m,mDNSs32 timenow)4790*4b22b933Srs200217 mDNSlocal mDNSs32 CheckNATMappings(mDNS *m, mDNSs32 timenow)
4791*4b22b933Srs200217 {
4792*4b22b933Srs200217 NATTraversalInfo *ptr = m->uDNS_info.NATTraversals;
4793*4b22b933Srs200217 mDNSs32 nextevent = timenow + MIN_UCAST_PERIODIC_EXEC;
4794*4b22b933Srs200217
4795*4b22b933Srs200217 while (ptr)
4796*4b22b933Srs200217 {
4797*4b22b933Srs200217 NATTraversalInfo *cur = ptr;
4798*4b22b933Srs200217 ptr = ptr->next;
4799*4b22b933Srs200217 if (cur->op != NATOp_AddrRequest || cur->state != NATState_Established) // no refresh necessary for established Add requests
4800*4b22b933Srs200217 {
4801*4b22b933Srs200217 if (cur->retry - timenow < 0)
4802*4b22b933Srs200217 {
4803*4b22b933Srs200217 if (cur->state == NATState_Established) RefreshNATMapping(cur, m);
4804*4b22b933Srs200217 else if (cur->state == NATState_Request || cur->state == NATState_Refresh)
4805*4b22b933Srs200217 {
4806*4b22b933Srs200217 if (cur->ntries >= NATMAP_MAX_TRIES) cur->ReceiveResponse(cur, m, mDNSNULL, 0); // may invalidate "cur"
4807*4b22b933Srs200217 else SendNATMsg(cur, m);
4808*4b22b933Srs200217 }
4809*4b22b933Srs200217 }
4810*4b22b933Srs200217 else if (cur->retry - nextevent < 0) nextevent = cur->retry;
4811*4b22b933Srs200217 }
4812*4b22b933Srs200217 }
4813*4b22b933Srs200217 return nextevent;
4814*4b22b933Srs200217 }
4815*4b22b933Srs200217
CheckQueries(mDNS * m,mDNSs32 timenow)4816*4b22b933Srs200217 mDNSlocal mDNSs32 CheckQueries(mDNS *m, mDNSs32 timenow)
4817*4b22b933Srs200217 {
4818*4b22b933Srs200217 DNSQuestion *q;
4819*4b22b933Srs200217 uDNS_GlobalInfo *u = &m->uDNS_info;
4820*4b22b933Srs200217 LLQ_Info *llq;
4821*4b22b933Srs200217 mDNSs32 sendtime;
4822*4b22b933Srs200217 mDNSs32 nextevent = timenow + MIN_UCAST_PERIODIC_EXEC;
4823*4b22b933Srs200217 DNSMessage msg;
4824*4b22b933Srs200217 mStatus err = mStatus_NoError;
4825*4b22b933Srs200217 mDNSu8 *end;
4826*4b22b933Srs200217 uDNS_QuestionInfo *info;
4827*4b22b933Srs200217
4828*4b22b933Srs200217 u->CurrentQuery = u->ActiveQueries;
4829*4b22b933Srs200217 while (u->CurrentQuery)
4830*4b22b933Srs200217 {
4831*4b22b933Srs200217 q = u->CurrentQuery;
4832*4b22b933Srs200217 info = &q->uDNS_info;
4833*4b22b933Srs200217 llq = info->llq;
4834*4b22b933Srs200217
4835*4b22b933Srs200217 if (!info->internal && ((!q->LongLived && !info->Answered) || (llq && llq->state < LLQ_Established)) &&
4836*4b22b933Srs200217 info->RestartTime + RESTART_GOODBYE_DELAY - timenow < 0)
4837*4b22b933Srs200217 {
4838*4b22b933Srs200217 // if we've been spinning on restart setup, and we have known answers, give goodbyes (they may be re-added later)
4839*4b22b933Srs200217 while (info->knownAnswers)
4840*4b22b933Srs200217 {
4841*4b22b933Srs200217 CacheRecord *cr = info->knownAnswers;
4842*4b22b933Srs200217 info->knownAnswers = info->knownAnswers->next;
4843*4b22b933Srs200217
4844*4b22b933Srs200217 m->mDNS_reentrancy++; // Increment to allow client to legally make mDNS API calls from the callback
4845*4b22b933Srs200217 q->QuestionCallback(m, q, &cr->resrec, mDNSfalse);
4846*4b22b933Srs200217 m->mDNS_reentrancy--; // Decrement to block mDNS API calls again
4847*4b22b933Srs200217 ufree(cr);
4848*4b22b933Srs200217 if (q != u->CurrentQuery) { debugf("CheckQueries - question removed via callback."); break; }
4849*4b22b933Srs200217 }
4850*4b22b933Srs200217 }
4851*4b22b933Srs200217 if (q != u->CurrentQuery) continue;
4852*4b22b933Srs200217
4853*4b22b933Srs200217 if (q->LongLived && llq->state != LLQ_Poll)
4854*4b22b933Srs200217 {
4855*4b22b933Srs200217 if (llq->state >= LLQ_InitialRequest && llq->state <= LLQ_Established)
4856*4b22b933Srs200217 {
4857*4b22b933Srs200217 if (llq->retry - timenow < 0)
4858*4b22b933Srs200217 {
4859*4b22b933Srs200217 // sanity check to avoid packet flood bugs
4860*4b22b933Srs200217 if (!llq->retry)
4861*4b22b933Srs200217 LogMsg("ERROR: retry timer not set for LLQ %##s in state %d", q->qname.c, llq->state);
4862*4b22b933Srs200217 else if (llq->state == LLQ_Established || llq->state == LLQ_Refresh)
4863*4b22b933Srs200217 sendLLQRefresh(m, q, llq->origLease);
4864*4b22b933Srs200217 else if (llq->state == LLQ_InitialRequest)
4865*4b22b933Srs200217 startLLQHandshake(m, llq, mDNSfalse);
4866*4b22b933Srs200217 else if (llq->state == LLQ_SecondaryRequest)
4867*4b22b933Srs200217 sendChallengeResponse(m, q, mDNSNULL);
4868*4b22b933Srs200217 else if (llq->state == LLQ_Retry)
4869*4b22b933Srs200217 { llq->ntries = 0; startLLQHandshake(m, llq, mDNSfalse); }
4870*4b22b933Srs200217 }
4871*4b22b933Srs200217 else if (llq->retry - nextevent < 0) nextevent = llq->retry;
4872*4b22b933Srs200217 }
4873*4b22b933Srs200217 }
4874*4b22b933Srs200217 else
4875*4b22b933Srs200217 {
4876*4b22b933Srs200217 sendtime = q->LastQTime + q->ThisQInterval;
4877*4b22b933Srs200217 if (m->SuppressStdPort53Queries &&
4878*4b22b933Srs200217 sendtime - m->SuppressStdPort53Queries < 0) // Don't allow sendtime to be earlier than SuppressStdPort53Queries
4879*4b22b933Srs200217 sendtime = m->SuppressStdPort53Queries;
4880*4b22b933Srs200217 if (sendtime - timenow < 0)
4881*4b22b933Srs200217 {
4882*4b22b933Srs200217 DNSServer *server = GetServerForName(&m->uDNS_info, &q->qname);
4883*4b22b933Srs200217 if (server)
4884*4b22b933Srs200217 {
4885*4b22b933Srs200217 if (server->teststate == DNSServer_Untested)
4886*4b22b933Srs200217 {
4887*4b22b933Srs200217 InitializeDNSMessage(&msg.h, newMessageID(&m->uDNS_info), uQueryFlags);
4888*4b22b933Srs200217 end = putQuestion(&msg, msg.data, msg.data + AbsoluteMaxDNSMessageData, DNSRelayTestQuestion, kDNSType_PTR, kDNSClass_IN);
4889*4b22b933Srs200217 }
4890*4b22b933Srs200217 else
4891*4b22b933Srs200217 err = constructQueryMsg(&msg, &end, q);
4892*4b22b933Srs200217 if (err) LogMsg("Error: uDNS_Idle - constructQueryMsg. Skipping question %##s", q->qname.c);
4893*4b22b933Srs200217 else
4894*4b22b933Srs200217 {
4895*4b22b933Srs200217 if (server->teststate != DNSServer_Failed)
4896*4b22b933Srs200217 err = mDNSSendDNSMessage(m, &msg, end, mDNSInterface_Any, &server->addr, UnicastDNSPort, -1, mDNSNULL);
4897*4b22b933Srs200217 m->SuppressStdPort53Queries = NonZeroTime(m->timenow + (mDNSPlatformOneSecond+99)/100);
4898*4b22b933Srs200217 q->LastQTime = timenow;
4899*4b22b933Srs200217 if (err) debugf("ERROR: uDNS_idle - mDNSSendDNSMessage - %ld", err); // surpress syslog messages if we have no network
4900*4b22b933Srs200217 else if (q->ThisQInterval < MAX_UCAST_POLL_INTERVAL) q->ThisQInterval = q->ThisQInterval * 2; // don't increase interval if send failed
4901*4b22b933Srs200217 }
4902*4b22b933Srs200217 }
4903*4b22b933Srs200217 }
4904*4b22b933Srs200217 else if (sendtime - nextevent < 0) nextevent = sendtime;
4905*4b22b933Srs200217 }
4906*4b22b933Srs200217 u->CurrentQuery = u->CurrentQuery->next;
4907*4b22b933Srs200217 }
4908*4b22b933Srs200217 return nextevent;
4909*4b22b933Srs200217 }
4910*4b22b933Srs200217
CheckRecordRegistrations(mDNS * m,mDNSs32 timenow)4911*4b22b933Srs200217 mDNSlocal mDNSs32 CheckRecordRegistrations(mDNS *m, mDNSs32 timenow)
4912*4b22b933Srs200217 {
4913*4b22b933Srs200217 AuthRecord *rr;
4914*4b22b933Srs200217 uDNS_RegInfo *rInfo;
4915*4b22b933Srs200217 uDNS_GlobalInfo *u = &m->uDNS_info;
4916*4b22b933Srs200217 mDNSs32 nextevent = timenow + MIN_UCAST_PERIODIC_EXEC;
4917*4b22b933Srs200217
4918*4b22b933Srs200217 //!!!KRS list should be pre-sorted by expiration
4919*4b22b933Srs200217 for (rr = u->RecordRegistrations; rr; rr = rr->next)
4920*4b22b933Srs200217 {
4921*4b22b933Srs200217 rInfo = &rr->uDNS_info;
4922*4b22b933Srs200217 if (rInfo->state == regState_Pending || rInfo->state == regState_DeregPending || rInfo->state == regState_UpdatePending || rInfo->state == regState_DeregDeferred || rInfo->state == regState_Refresh)
4923*4b22b933Srs200217 {
4924*4b22b933Srs200217 if (rr->LastAPTime + rr->ThisAPInterval - timenow < 0)
4925*4b22b933Srs200217 {
4926*4b22b933Srs200217 #if MDNS_DEBUGMSGS
4927*4b22b933Srs200217 char *op = "(unknown operation)";
4928*4b22b933Srs200217 if (rInfo->state == regState_Pending) op = "registration";
4929*4b22b933Srs200217 else if (rInfo->state == regState_DeregPending) op = "deregistration";
4930*4b22b933Srs200217 else if (rInfo->state == regState_Refresh) op = "refresh";
4931*4b22b933Srs200217 debugf("Retransmit record %s %##s", op, rr->resrec.name->c);
4932*4b22b933Srs200217 #endif
4933*4b22b933Srs200217 //LogMsg("Retransmit record %##s", rr->resrec.name->c);
4934*4b22b933Srs200217 if (rInfo->state == regState_DeregPending) SendRecordDeregistration(m, rr);
4935*4b22b933Srs200217 else sendRecordRegistration(m, rr);
4936*4b22b933Srs200217 }
4937*4b22b933Srs200217 if (rr->LastAPTime + rr->ThisAPInterval - nextevent < 0) nextevent = rr->LastAPTime + rr->ThisAPInterval;
4938*4b22b933Srs200217 }
4939*4b22b933Srs200217 if (rInfo->lease && rInfo->state == regState_Registered)
4940*4b22b933Srs200217 {
4941*4b22b933Srs200217 if (rInfo->expire - timenow < 0)
4942*4b22b933Srs200217 {
4943*4b22b933Srs200217 debugf("refreshing record %##s", rr->resrec.name->c);
4944*4b22b933Srs200217 rInfo->state = regState_Refresh;
4945*4b22b933Srs200217 sendRecordRegistration(m, rr);
4946*4b22b933Srs200217 }
4947*4b22b933Srs200217 if (rInfo->expire - nextevent < 0) nextevent = rInfo->expire;
4948*4b22b933Srs200217 }
4949*4b22b933Srs200217 }
4950*4b22b933Srs200217 return nextevent;
4951*4b22b933Srs200217 }
4952*4b22b933Srs200217
CheckServiceRegistrations(mDNS * m,mDNSs32 timenow)4953*4b22b933Srs200217 mDNSlocal mDNSs32 CheckServiceRegistrations(mDNS *m, mDNSs32 timenow)
4954*4b22b933Srs200217 {
4955*4b22b933Srs200217 ServiceRecordSet *s = m->uDNS_info.ServiceRegistrations;
4956*4b22b933Srs200217 uDNS_RegInfo *rInfo;
4957*4b22b933Srs200217 mDNSs32 nextevent = timenow + MIN_UCAST_PERIODIC_EXEC;
4958*4b22b933Srs200217
4959*4b22b933Srs200217 // Note: ServiceRegistrations list is in the order they were created; important for in-order event delivery
4960*4b22b933Srs200217 while (s)
4961*4b22b933Srs200217 {
4962*4b22b933Srs200217 ServiceRecordSet *srs = s;
4963*4b22b933Srs200217 // NOTE: Must advance s here -- SendServiceDeregistration may delete the object we're looking at,
4964*4b22b933Srs200217 // and then if we tried to do srs = srs->next at the end we'd be referencing a dead object
4965*4b22b933Srs200217 s = s->next;
4966*4b22b933Srs200217
4967*4b22b933Srs200217 rInfo = &srs->uDNS_info;
4968*4b22b933Srs200217 if (rInfo->state == regState_Pending || rInfo->state == regState_DeregPending || rInfo->state == regState_DeregDeferred || rInfo->state == regState_Refresh || rInfo->state == regState_UpdatePending)
4969*4b22b933Srs200217 {
4970*4b22b933Srs200217 if (srs->RR_SRV.LastAPTime + srs->RR_SRV.ThisAPInterval - timenow < 0)
4971*4b22b933Srs200217 {
4972*4b22b933Srs200217 #if MDNS_DEBUGMSGS
4973*4b22b933Srs200217 char *op = "unknown";
4974*4b22b933Srs200217 if (rInfo->state == regState_Pending) op = "registration";
4975*4b22b933Srs200217 else if (rInfo->state == regState_DeregPending) op = "deregistration";
4976*4b22b933Srs200217 else if (rInfo->state == regState_Refresh) op = "refresh";
4977*4b22b933Srs200217 else if (rInfo->state == regState_UpdatePending) op = "txt record update";
4978*4b22b933Srs200217 debugf("Retransmit service %s %##s", op, srs->RR_SRV.resrec.name->c);
4979*4b22b933Srs200217 #endif
4980*4b22b933Srs200217 if (rInfo->state == regState_DeregPending) { SendServiceDeregistration(m, srs); continue; }
4981*4b22b933Srs200217 else SendServiceRegistration (m, srs);
4982*4b22b933Srs200217 }
4983*4b22b933Srs200217 if (nextevent - srs->RR_SRV.LastAPTime + srs->RR_SRV.ThisAPInterval > 0)
4984*4b22b933Srs200217 nextevent = srs->RR_SRV.LastAPTime + srs->RR_SRV.ThisAPInterval;
4985*4b22b933Srs200217 }
4986*4b22b933Srs200217
4987*4b22b933Srs200217 if (rInfo->lease && rInfo->state == regState_Registered)
4988*4b22b933Srs200217 {
4989*4b22b933Srs200217 if (rInfo->expire - timenow < 0)
4990*4b22b933Srs200217 {
4991*4b22b933Srs200217 debugf("refreshing service %##s", srs->RR_SRV.resrec.name->c);
4992*4b22b933Srs200217 rInfo->state = regState_Refresh;
4993*4b22b933Srs200217 SendServiceRegistration(m, srs);
4994*4b22b933Srs200217 }
4995*4b22b933Srs200217 if (rInfo->expire - nextevent < 0) nextevent = rInfo->expire;
4996*4b22b933Srs200217 }
4997*4b22b933Srs200217 }
4998*4b22b933Srs200217 return nextevent;
4999*4b22b933Srs200217 }
5000*4b22b933Srs200217
uDNS_Execute(mDNS * const m)5001*4b22b933Srs200217 mDNSexport void uDNS_Execute(mDNS *const m)
5002*4b22b933Srs200217 {
5003*4b22b933Srs200217 uDNS_GlobalInfo *u = &m->uDNS_info;
5004*4b22b933Srs200217 mDNSs32 nexte, timenow = mDNSPlatformTimeNow(m);
5005*4b22b933Srs200217
5006*4b22b933Srs200217 u->nextevent = timenow + MIN_UCAST_PERIODIC_EXEC;
5007*4b22b933Srs200217
5008*4b22b933Srs200217 if (u->DelaySRVUpdate && u->NextSRVUpdate - timenow < 0)
5009*4b22b933Srs200217 {
5010*4b22b933Srs200217 u->DelaySRVUpdate = mDNSfalse;
5011*4b22b933Srs200217 UpdateSRVRecords(m);
5012*4b22b933Srs200217 }
5013*4b22b933Srs200217
5014*4b22b933Srs200217 nexte = CheckNATMappings(m, timenow);
5015*4b22b933Srs200217 if (nexte - u->nextevent < 0) u->nextevent = nexte;
5016*4b22b933Srs200217
5017*4b22b933Srs200217 if (m->SuppressStdPort53Queries && m->timenow - m->SuppressStdPort53Queries >= 0)
5018*4b22b933Srs200217 m->SuppressStdPort53Queries = 0; // If suppression time has passed, clear it
5019*4b22b933Srs200217
5020*4b22b933Srs200217 nexte = CheckQueries(m, timenow);
5021*4b22b933Srs200217 if (nexte - u->nextevent < 0) u->nextevent = nexte;
5022*4b22b933Srs200217
5023*4b22b933Srs200217 nexte = CheckRecordRegistrations(m, timenow);
5024*4b22b933Srs200217 if (nexte - u->nextevent < 0) u->nextevent = nexte;
5025*4b22b933Srs200217
5026*4b22b933Srs200217 nexte = CheckServiceRegistrations(m, timenow);
5027*4b22b933Srs200217 if (nexte - u->nextevent < 0) u->nextevent = nexte;
5028*4b22b933Srs200217
5029*4b22b933Srs200217 }
5030*4b22b933Srs200217
5031*4b22b933Srs200217 // ***************************************************************************
5032*4b22b933Srs200217 #if COMPILER_LIKES_PRAGMA_MARK
5033*4b22b933Srs200217 #pragma mark - Startup, Shutdown, and Sleep
5034*4b22b933Srs200217 #endif
5035*4b22b933Srs200217
5036*4b22b933Srs200217 // DeregisterActive causes active LLQs to be removed from the server, e.g. before sleep. Pass false
5037*4b22b933Srs200217 // following a location change, as the server will reject deletions from a source address different
5038*4b22b933Srs200217 // from the address on which the LLQ was created.
5039*4b22b933Srs200217
SuspendLLQs(mDNS * m,mDNSBool DeregisterActive)5040*4b22b933Srs200217 mDNSlocal void SuspendLLQs(mDNS *m, mDNSBool DeregisterActive)
5041*4b22b933Srs200217 {
5042*4b22b933Srs200217 DNSQuestion *q;
5043*4b22b933Srs200217 LLQ_Info *llq;
5044*4b22b933Srs200217 for (q = m->uDNS_info.ActiveQueries; q; q = q->next)
5045*4b22b933Srs200217 {
5046*4b22b933Srs200217 llq = q->uDNS_info.llq;
5047*4b22b933Srs200217 if (q->LongLived && llq)
5048*4b22b933Srs200217 {
5049*4b22b933Srs200217 if (llq->state == LLQ_GetZoneInfo)
5050*4b22b933Srs200217 {
5051*4b22b933Srs200217 debugf("Marking %##s suspend-deferred", q->qname.c);
5052*4b22b933Srs200217 llq->state = LLQ_SuspendDeferred; // suspend once we're done getting zone info
5053*4b22b933Srs200217 }
5054*4b22b933Srs200217 else if (llq->state < LLQ_Suspended)
5055*4b22b933Srs200217 {
5056*4b22b933Srs200217 if (DeregisterActive && (llq->state == LLQ_Established || llq->state == LLQ_Refresh))
5057*4b22b933Srs200217 { debugf("Deleting LLQ %##s", q->qname.c); sendLLQRefresh(m, q, 0); }
5058*4b22b933Srs200217 debugf("Marking %##s suspended", q->qname.c);
5059*4b22b933Srs200217 llq->state = LLQ_Suspended;
5060*4b22b933Srs200217 ubzero(llq->id, 8);
5061*4b22b933Srs200217 }
5062*4b22b933Srs200217 else if (llq->state == LLQ_Poll) { debugf("Marking %##s suspended-poll", q->qname.c); llq->state = LLQ_SuspendedPoll; }
5063*4b22b933Srs200217 if (llq->NATMap) llq->NATMap = mDNSfalse; // may not need nat mapping if we restart with new route
5064*4b22b933Srs200217 }
5065*4b22b933Srs200217 }
5066*4b22b933Srs200217 CheckForUnreferencedLLQMapping(m);
5067*4b22b933Srs200217 }
5068*4b22b933Srs200217
RestartQueries(mDNS * m)5069*4b22b933Srs200217 mDNSlocal void RestartQueries(mDNS *m)
5070*4b22b933Srs200217 {
5071*4b22b933Srs200217 uDNS_GlobalInfo *u = &m->uDNS_info;
5072*4b22b933Srs200217 DNSQuestion *q;
5073*4b22b933Srs200217 LLQ_Info *llqInfo;
5074*4b22b933Srs200217 mDNSs32 timenow = mDNSPlatformTimeNow(m);
5075*4b22b933Srs200217
5076*4b22b933Srs200217 u->CurrentQuery = u->ActiveQueries;
5077*4b22b933Srs200217 while (u->CurrentQuery)
5078*4b22b933Srs200217 {
5079*4b22b933Srs200217 q = u->CurrentQuery;
5080*4b22b933Srs200217 u->CurrentQuery = u->CurrentQuery->next;
5081*4b22b933Srs200217 llqInfo = q->uDNS_info.llq;
5082*4b22b933Srs200217 q->uDNS_info.RestartTime = timenow;
5083*4b22b933Srs200217 q->uDNS_info.Answered = mDNSfalse;
5084*4b22b933Srs200217 if (q->LongLived)
5085*4b22b933Srs200217 {
5086*4b22b933Srs200217 if (!llqInfo) { LogMsg("Error: RestartQueries - %##s long-lived with NULL info", q->qname.c); continue; }
5087*4b22b933Srs200217 if (llqInfo->state == LLQ_Suspended || llqInfo->state == LLQ_NatMapWait)
5088*4b22b933Srs200217 {
5089*4b22b933Srs200217 llqInfo->ntries = -1;
5090*4b22b933Srs200217 llqInfo->deriveRemovesOnResume = mDNStrue;
5091*4b22b933Srs200217 startLLQHandshake(m, llqInfo, mDNStrue); // we set defer to true since several events that may generate restarts often arrive in rapid succession, and this cuts unnecessary packets
5092*4b22b933Srs200217 }
5093*4b22b933Srs200217 else if (llqInfo->state == LLQ_SuspendDeferred)
5094*4b22b933Srs200217 llqInfo->state = LLQ_GetZoneInfo; // we never finished getting zone data - proceed as usual
5095*4b22b933Srs200217 else if (llqInfo->state == LLQ_SuspendedPoll)
5096*4b22b933Srs200217 {
5097*4b22b933Srs200217 // if we were polling, we may have had bad zone data due to firewall, etc. - refetch
5098*4b22b933Srs200217 llqInfo->ntries = 0;
5099*4b22b933Srs200217 llqInfo->deriveRemovesOnResume = mDNStrue;
5100*4b22b933Srs200217 llqInfo->state = LLQ_GetZoneInfo;
5101*4b22b933Srs200217 startGetZoneData(&q->qname, m, mDNSfalse, mDNStrue, startLLQHandshakeCallback, llqInfo);
5102*4b22b933Srs200217 }
5103*4b22b933Srs200217 }
5104*4b22b933Srs200217 else { q->LastQTime = timenow; q->ThisQInterval = INIT_UCAST_POLL_INTERVAL; } // trigger poll in 1 second (to reduce packet rate when restarts come in rapid succession)
5105*4b22b933Srs200217 }
5106*4b22b933Srs200217 }
5107*4b22b933Srs200217
mDNS_UpdateLLQs(mDNS * m)5108*4b22b933Srs200217 mDNSexport void mDNS_UpdateLLQs(mDNS *m)
5109*4b22b933Srs200217 {
5110*4b22b933Srs200217 uDNS_GlobalInfo *u = &m->uDNS_info;
5111*4b22b933Srs200217
5112*4b22b933Srs200217 mDNS_Lock(m);
5113*4b22b933Srs200217 if (u->LLQNatInfo)
5114*4b22b933Srs200217 {
5115*4b22b933Srs200217 DeleteNATPortMapping(m, u->LLQNatInfo, mDNSNULL);
5116*4b22b933Srs200217 FreeNATInfo(m, u->LLQNatInfo); // routine clears u->LLQNatInfo ptr
5117*4b22b933Srs200217 }
5118*4b22b933Srs200217 SuspendLLQs(m, mDNStrue);
5119*4b22b933Srs200217 RestartQueries(m);
5120*4b22b933Srs200217 mDNS_Unlock(m);
5121*4b22b933Srs200217 }
5122*4b22b933Srs200217
5123*4b22b933Srs200217 // simplest sleep logic - rather than having sleep states that must be dealt with explicitly in all parts of
5124*4b22b933Srs200217 // the code, we simply send a deregistration, and put the service in Refresh state, with a timeout far enough
5125*4b22b933Srs200217 // in the future that we'll sleep (or the sleep will be cancelled) before it is retransmitted. Then to wake,
5126*4b22b933Srs200217 // we just move up the timers.
5127*4b22b933Srs200217
5128*4b22b933Srs200217
5129*4b22b933Srs200217
SleepRecordRegistrations(mDNS * m)5130*4b22b933Srs200217 mDNSlocal void SleepRecordRegistrations(mDNS *m)
5131*4b22b933Srs200217 {
5132*4b22b933Srs200217 DNSMessage msg;
5133*4b22b933Srs200217 AuthRecord *rr = m->uDNS_info.RecordRegistrations;
5134*4b22b933Srs200217 mDNSs32 timenow = mDNSPlatformTimeNow(m);
5135*4b22b933Srs200217
5136*4b22b933Srs200217 while (rr)
5137*4b22b933Srs200217 {
5138*4b22b933Srs200217 if (rr->uDNS_info.state == regState_Registered ||
5139*4b22b933Srs200217 rr->uDNS_info.state == regState_Refresh)
5140*4b22b933Srs200217 {
5141*4b22b933Srs200217 mDNSu8 *ptr = msg.data, *end = (mDNSu8 *)&msg + sizeof(DNSMessage);
5142*4b22b933Srs200217 InitializeDNSMessage(&msg.h, newMessageID(&m->uDNS_info), UpdateReqFlags);
5143*4b22b933Srs200217
5144*4b22b933Srs200217 // construct deletion update
5145*4b22b933Srs200217 ptr = putZone(&msg, ptr, end, &rr->uDNS_info.zone, mDNSOpaque16fromIntVal(rr->resrec.rrclass));
5146*4b22b933Srs200217 if (!ptr) { LogMsg("Error: SleepRecordRegistrations - could not put zone"); return; }
5147*4b22b933Srs200217 ptr = putDeletionRecord(&msg, ptr, &rr->resrec);
5148*4b22b933Srs200217 if (!ptr) { LogMsg("Error: SleepRecordRegistrations - could not put deletion record"); return; }
5149*4b22b933Srs200217
5150*4b22b933Srs200217 mDNSSendDNSMessage(m, &msg, ptr, mDNSInterface_Any, &rr->uDNS_info.ns, rr->uDNS_info.port, -1, GetAuthInfoForName(&m->uDNS_info, rr->resrec.name));
5151*4b22b933Srs200217 rr->uDNS_info.state = regState_Refresh;
5152*4b22b933Srs200217 rr->LastAPTime = timenow;
5153*4b22b933Srs200217 rr->ThisAPInterval = 300 * mDNSPlatformOneSecond;
5154*4b22b933Srs200217 }
5155*4b22b933Srs200217 rr = rr->next;
5156*4b22b933Srs200217 }
5157*4b22b933Srs200217 }
5158*4b22b933Srs200217
WakeRecordRegistrations(mDNS * m)5159*4b22b933Srs200217 mDNSlocal void WakeRecordRegistrations(mDNS *m)
5160*4b22b933Srs200217 {
5161*4b22b933Srs200217 mDNSs32 timenow = mDNSPlatformTimeNow(m);
5162*4b22b933Srs200217 AuthRecord *rr = m->uDNS_info.RecordRegistrations;
5163*4b22b933Srs200217
5164*4b22b933Srs200217 while (rr)
5165*4b22b933Srs200217 {
5166*4b22b933Srs200217 if (rr->uDNS_info.state == regState_Refresh)
5167*4b22b933Srs200217 {
5168*4b22b933Srs200217 // trigger slightly delayed refresh (we usually get this message before kernel is ready to send packets)
5169*4b22b933Srs200217 rr->LastAPTime = timenow;
5170*4b22b933Srs200217 rr->ThisAPInterval = INIT_UCAST_POLL_INTERVAL;
5171*4b22b933Srs200217 }
5172*4b22b933Srs200217 rr = rr->next;
5173*4b22b933Srs200217 }
5174*4b22b933Srs200217 }
5175*4b22b933Srs200217
SleepServiceRegistrations(mDNS * m)5176*4b22b933Srs200217 mDNSlocal void SleepServiceRegistrations(mDNS *m)
5177*4b22b933Srs200217 {
5178*4b22b933Srs200217 ServiceRecordSet *srs = m->uDNS_info.ServiceRegistrations;
5179*4b22b933Srs200217 while(srs)
5180*4b22b933Srs200217 {
5181*4b22b933Srs200217 uDNS_RegInfo *info = &srs->uDNS_info;
5182*4b22b933Srs200217 NATTraversalInfo *nat = info->NATinfo;
5183*4b22b933Srs200217
5184*4b22b933Srs200217 if (nat)
5185*4b22b933Srs200217 {
5186*4b22b933Srs200217 if (nat->state == NATState_Established || nat->state == NATState_Refresh || nat->state == NATState_Legacy)
5187*4b22b933Srs200217 DeleteNATPortMapping(m, nat, srs);
5188*4b22b933Srs200217 nat->reg.ServiceRegistration = mDNSNULL;
5189*4b22b933Srs200217 srs->uDNS_info.NATinfo = mDNSNULL;
5190*4b22b933Srs200217 FreeNATInfo(m, nat);
5191*4b22b933Srs200217 }
5192*4b22b933Srs200217
5193*4b22b933Srs200217 if (info->state == regState_UpdatePending)
5194*4b22b933Srs200217 {
5195*4b22b933Srs200217 // act as if the update succeeded, since we're about to delete the name anyway
5196*4b22b933Srs200217 AuthRecord *txt = &srs->RR_TXT;
5197*4b22b933Srs200217 uDNS_RegInfo *txtInfo = &txt->uDNS_info;
5198*4b22b933Srs200217 info->state = regState_Registered;
5199*4b22b933Srs200217 // deallocate old RData
5200*4b22b933Srs200217 if (txtInfo->UpdateRDCallback) txtInfo->UpdateRDCallback(m, txt, txtInfo->OrigRData);
5201*4b22b933Srs200217 SetNewRData(&txt->resrec, txtInfo->InFlightRData, txtInfo->InFlightRDLen);
5202*4b22b933Srs200217 txtInfo->OrigRData = mDNSNULL;
5203*4b22b933Srs200217 txtInfo->InFlightRData = mDNSNULL;
5204*4b22b933Srs200217 }
5205*4b22b933Srs200217
5206*4b22b933Srs200217 if (info->state == regState_Registered || info->state == regState_Refresh)
5207*4b22b933Srs200217 {
5208*4b22b933Srs200217 mDNSOpaque16 origid = srs->uDNS_info.id;
5209*4b22b933Srs200217 info->state = regState_DeregPending; // state expected by SendDereg()
5210*4b22b933Srs200217 SendServiceDeregistration(m, srs);
5211*4b22b933Srs200217 info->id = origid;
5212*4b22b933Srs200217 info->state = regState_NoTarget; // when we wake, we'll re-register (and optionally nat-map) once our address record completes
5213*4b22b933Srs200217 srs->RR_SRV.resrec.rdata->u.srv.target.c[0] = 0;
5214*4b22b933Srs200217 }
5215*4b22b933Srs200217 srs = srs->next;
5216*4b22b933Srs200217 }
5217*4b22b933Srs200217 }
5218*4b22b933Srs200217
WakeServiceRegistrations(mDNS * m)5219*4b22b933Srs200217 mDNSlocal void WakeServiceRegistrations(mDNS *m)
5220*4b22b933Srs200217 {
5221*4b22b933Srs200217 mDNSs32 timenow = mDNSPlatformTimeNow(m);
5222*4b22b933Srs200217 ServiceRecordSet *srs = m->uDNS_info.ServiceRegistrations;
5223*4b22b933Srs200217 while(srs)
5224*4b22b933Srs200217 {
5225*4b22b933Srs200217 if (srs->uDNS_info.state == regState_Refresh)
5226*4b22b933Srs200217 {
5227*4b22b933Srs200217 // trigger slightly delayed refresh (we usually get this message before kernel is ready to send packets)
5228*4b22b933Srs200217 srs->RR_SRV.LastAPTime = timenow;
5229*4b22b933Srs200217 srs->RR_SRV.ThisAPInterval = INIT_UCAST_POLL_INTERVAL;
5230*4b22b933Srs200217 }
5231*4b22b933Srs200217 srs = srs->next;
5232*4b22b933Srs200217 }
5233*4b22b933Srs200217 }
5234*4b22b933Srs200217
uDNS_Init(mDNS * const m)5235*4b22b933Srs200217 mDNSexport void uDNS_Init(mDNS *const m)
5236*4b22b933Srs200217 {
5237*4b22b933Srs200217 mDNSPlatformMemZero(&m->uDNS_info, sizeof(uDNS_GlobalInfo));
5238*4b22b933Srs200217 m->uDNS_info.nextevent = m->timenow_last + 0x78000000;
5239*4b22b933Srs200217 }
5240*4b22b933Srs200217
uDNS_Sleep(mDNS * const m)5241*4b22b933Srs200217 mDNSexport void uDNS_Sleep(mDNS *const m)
5242*4b22b933Srs200217 {
5243*4b22b933Srs200217 SuspendLLQs(m, mDNStrue);
5244*4b22b933Srs200217 SleepServiceRegistrations(m);
5245*4b22b933Srs200217 SleepRecordRegistrations(m);
5246*4b22b933Srs200217 }
5247*4b22b933Srs200217
uDNS_Wake(mDNS * const m)5248*4b22b933Srs200217 mDNSexport void uDNS_Wake(mDNS *const m)
5249*4b22b933Srs200217 {
5250*4b22b933Srs200217 RestartQueries(m);
5251*4b22b933Srs200217 WakeServiceRegistrations(m);
5252*4b22b933Srs200217 WakeRecordRegistrations(m);
5253*4b22b933Srs200217 }
5254